2

假设我从一个函数 开始foo(),它是正确的但样式很差:

int foo(void)
{
    // Some comment
    int b;
    int    a;

    getAandB(&a, &b);

    return a+b;
}

我想重新格式化此代码块而不进行任何功能更改:

int foo(void)
{
    // A more descriptive comment
    int a, b;

    getAandB(&a, &b);

    return a + b;
}

有没有我可以用来证明这两个块在功能上等效的工具?让我们假设重新构建整个代码库不是一种选择,我只想单独测试这个代码块。我将无法链接它,因为getAandB()在其他地方定义。

在这种情况下,是否可以使用一些工具组合来证明功能等价?

4

5 回答 5

5

你这里有点问题。假设getAandB定义如下:

void getAandB(int *a, int *b) {
    if std::less<int*>()(a, b) {
        *a = 1;
        *b = 2;
    } else {
        *a = 2;
        *b = 3;
    }
}

那么你对函数所做的改变foo很可能会对行为产生影响(因为改变变量的声明顺序可能会改变它们在堆栈上的位置)。

现在诚然,它正在改变的行为是未指定的,并且很可能您可以对其进行许多无害的更改,foo这将改变局部变量在堆栈上的布局方式,从而改变这种特殊情况下的行为getAandB。但是你可能用来测试等价性的任何工具都不会知道你是否关心这种可能性(尽管它的定义getAandB可能会排除它)。

您可以使用允许更改未指定行为的“等效”定义——例如,“as-if”规则。在优化器中,为了了解代码在“as-if”规则下是否等效,需要付出很多努力,但通常它们通过应用一系列已知可以的转换来工作,而不是通过获取两位代码并测试它们。

于 2013-10-17T16:39:36.930 回答
1

Uncrustify,一个开源项目可能对类似 C 的语言有用。

另一个,用得比较多的是AStyle

于 2013-10-17T16:00:27.477 回答
1

测试类的好工具是单元测试,例如boost::testcppunit。测试相同的类是否以相同的方式通过测试,然后它们在功能上是等效的。显然,您必须选择适当的测试。

于 2013-10-17T16:01:49.253 回答
1

我认为通过在翻译你的 2 个函数后比较编译器生成的AST ,你会得到最好的结果。可能最简单的方法是使用clang,因为它旨在轻松访问 AST 并基于它制作工具。

于 2013-10-17T16:05:41.880 回答
0

如果您想使用检查生成的程序集方法,您可以这样做。

我假设您的两个函数被放入两个文件中,a.c并且b.c

$ gcc -O0 -S a.c
$ gcc -O0 -S b.c
$ diff a.s b.s
1c1
<  .file "a.c"
---
>  .file "b.c"
13,14c13,14
<  leaq -4(%rbp), %rsi
<  leaq -8(%rbp), %rdi
---
>  leaq -8(%rbp), %rsi
>  leaq -4(%rbp), %rdi
17,18c17,18
<  movl -8(%rbp), %edx
<  movl -4(%rbp), %eax
---
>  movl -4(%rbp), %edx
>  movl -8(%rbp), %eax
$ 

我们关闭任何优化 (-O0) 以防止任何工件优化。

所以有点令人惊讶的是,这两个函数的 gcc (4.1.2) 输出略有不同。但是仔细观察一下,我们就会明白为什么 - 在第一个函数中,声明b是 before a,所以在堆栈上b是 above a,但在第二个函数中,它是相反的。

因此,如果我交换a并且b现在看到生成的程序集实际上是相同的:

$ gcc -O0 -S b1.c
$ diff a.s b1.s
1c1
<  .file "a.c"
---
>  .file "b1.c"
$ 

或者,如果您只关心生成的程序集是否不同,而不关心生成的程序集实际上是什么,那么您可以在一个fancy-schmancy bash 命令中完成这一切:

$ diff --brief <(cat a.c | gcc -O0 -S -xc - -o-) <(cat b.c | gcc -O0 -S -xc - -o-)
Files /dev/fd/63 and /dev/fd/62 differ
$ echo $?
1
$ diff --brief <(cat a.c | gcc -O0 -S -xc - -o-) <(cat b1.c | gcc -O0 -S -xc - -o-)
$ echo $?
0
$ 
于 2013-10-17T16:37:36.783 回答