3

(C) 如果我有一个包含 if which 的函数,如果条件为真,则可以返回某个值,然后 else 返回不同的值。使用 else 或不打扰是或多或少有效吗?

IE ...

int foo (int a) {
    if ((a > 0) && (a < SOME_LIMIT)) {
        b = a //maybe b is some global or something
        return 0;
    } else {
        return 1;
    }
    return 0;
}

要不就

int foo (int a) {
    if ((a > 0) && (a < SOME_LIMIT)) {
        b = a //maybe b is some global or something
        return 0;
    }
    return 1;
}

假设 GCC,第一个实现会导致编译后的代码与第二个不同吗?

我需要在这里尽可能高效,因此可能减少 else 的分支会很好 - 但从风格上讲,我内心的强迫症不喜欢看到返回不是 0 或 void 作为函数中的最后一条指令不太清楚发生了什么。因此,如果无论如何它都会被删除,那么我可以将 else 留在那里......

4

6 回答 6

8

您可以使用选项运行 gcc-O3 -S以生成优化的汇编代码,因此您可以查看(并比较)优化的汇编。我对您的源代码进行了以下更改以使其编译。

文件交流

int b;                                                                         

int foo (int a) {             
    if ((a > 0) && (a < 5000)) {  
        b = a;                                                    
        return 0;                                                        
    } else {                                                                   
        return 1;             
    }                                       
    return 0;                          
}

文件bc

int b;                                                                         
int foo (int a) {                                                             
    if ((a > 0) && (a < 5000)) {
        b = a;
        return 0;
    }       
    return 1;                                                                  
}

使用创建的文件编译ac时。在我的机器上看起来像这样:gcc -O3 -S a.c

               .file      "a.c"
               .text
               .p2align 4,,15
               .globl     foo
               .type      foo, @function
foo:
.LFB0:
               .cfi_startproc
               movl       4(%esp), %edx
               movl       $1, %eax
               leal       -1(%edx), %ecx
               cmpl       $4998, %ecx
               ja         .L2
               movl       %edx, b
               xorb       %al, %al
.L2:
               rep
               ret
               .cfi_endproc
.LFE0:
               .size      foo, .-foo
               .comm      b,4,4
               .ident     "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
               .section   .note.GNU-stack,"",@progbits

使用文件bs编译bc时,会创建。在我的机器上看起来像这样:gcc -O3 -S b.c

               .file      "b.c"
               .text
               .p2align 4,,15
               .globl     foo
               .type      foo, @function
foo:
.LFB0:
               .cfi_startproc
               movl       4(%esp), %edx
               movl       $1, %eax
               leal       -1(%edx), %ecx
               cmpl       $4998, %ecx
               ja         .L2
               movl       %edx, b
               xorb       %al, %al
.L2:
               rep
               ret
               .cfi_endproc
.LFE0:
               .size      foo, .-foo
               .comm      b,4,4
               .ident     "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
               .section   .note.GNU-stack,"",@progbits

请注意,组装的实现foo:是相同的。因此,在这种情况下,使用此版本的 GCC,您编写代码的方式并不重要。

于 2013-07-10T15:29:49.497 回答
1

检查两个实现之间的目标文件。放置一个程序集标题,例如

 PortionInQuestion: 

然后它将作为标签显示在您的程序集文件中,您可以看到生成的程序集有何不同。它们可能根本没有区别(因为优化),或者它们可能完全不同。如果没有看到原始程序集,就无法判断编译器是如何优化它的。

于 2013-07-10T15:15:21.397 回答
1

return 0;在第一个示例中,您不会走到最后。我会说你的第二个至少在风格上更清晰。同一件事的代码越少通常是一件好事。

关于性能,如果您喜欢这样的东西或分析代码,您可以检查程序集可执行文件并查看是否存在实际差异。我的赌注无关紧要。

最后,如果您的编译器支持优化标志,请使用它们!

于 2013-07-10T15:17:32.287 回答
1

当然,这取决于编译器。我猜市场上的每个(体面的)编译器在这两种情况下都会产生完全相同的输出。然而,任何关于优化的书都不鼓励尝试这种微优化!

选择可读性更好的表格。

于 2013-07-10T15:18:35.660 回答
1

我会这样写...

int foo (int a) {
    if ((a > 0) && (a < SOME_LIMIT)) {
        b = a //maybe b is some global or something
        return 0;
    } else {
        return 1;
    }
}

整个函数只是一个布尔值,用于条件 b 的值大于零且小于某个常数。if 语句是返回的条件。无需向函数添加默认返回。默认返回将使 if 条件无效。

于 2013-07-10T15:26:50.280 回答
1
int foo (int a) {

     /* Nothing to do: get out of here */
    if (a <= 0 || a >= SOME_LIMIT) return 1;

    b = a; // maybe b is some global or something

    return 0;
}

在效率方面几乎没有任何差异(最昂贵的部分是函数调用加上返回)。

对于人类读者来说,“缩进”最少的代码(例如上面的代码)是最容易阅读和理解的。

顺便说一句,生成的汇编程序在我看来也非常小,完全等同于if (a >0 && a < LIMIT)表单。

        .file   "return.c"
        .text
        .p2align 4,,15
        .globl  foo
        .type   foo, @function
foo:
.LFB0:
        .cfi_startproc
        leal    -1(%rdi), %edx
        movl    $1, %eax
        cmpl    $2998, %edx
        ja      .L2
        movl    %edi, b(%rip)
        xorb    %al, %al
.L2:
        rep
        ret
        .cfi_endproc
.LFE0:
        .size   foo, .-foo
        .globl  b
        .bss
        .align 16
        .type   b, @object
        .size   b, 4
b:
        .zero   4
        .ident  "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
        .section        .note.GNU-stack,"",@progbits
于 2013-07-10T15:29:55.813 回答