哪一个更适合在C和C ++编程中使用?

时间:2017-05-18 06:57:47

标签: c++ c performance if-statement optimization

以下两个代码段之间有什么区别吗?哪一个更好用?其中一个更快吗?

案例1:

int f(int x) 
{
    int a;
    if(x)
        a = 42;
    else
        a = 0;
    return a; 
}

案例2:

int f(int x) 
{
    int a;
    if(x)
        a = 42;
    return a; 
}

6 个答案:

答案 0 :(得分:4)

实际上两个片段都可以返回完全不同的结果,所以没有更好的...

案例2 中,您可以返回非初始化变量 a ,这可能会导致非零的垃圾值......

如果你的意思是:

int f(int x) 
{
    int a = 0;
    if(x)
        a = 42;
    return a; 
}

然后我会说更好,因为更紧凑(但你只保存一个其他的,没有多少计算浪费)

答案 1 :(得分:3)

问题不是"哪一个更好"。问题是"两者都有效吗?"

答案是不,他们不会同时工作。一个是正​​确的,另一个是不可能的。因此,性能甚至不是问题。

以下结果导致a具有"不确定值"或者"未指明的值"在c99标准中提到的3.17.2和3.17.3节(可能是后者,虽然我不清楚。)

int a;
if(x)
    a = 42;
return a; 

这反过来意味着该函数将返回一个未指定的值。这意味着绝对无法保证您将获得什么价值。

如果你不幸,你可能会得到零,因此继续使用上面这段可怕的代码而不知道你以后会遇到很多麻烦。

如果你幸运,你会立刻得到像0x719Ab32d这样的东西,所以你会立刻知道你搞砸了。

如果你试图编译它,任何体面的C编译器都会给你一个警告,所以你问这个问题意味着你没有启用足够数量的警告。在没有启用最大可能警告数量的情况下,不要尝试编写C代码(或任何代码);它永远不会带来任何好处。了解如何在C编译器上启用警告,并尽可能多地启用它们。

答案 2 :(得分:2)

注意:我假设你的第二个片段中未初始化的a是一个类型,它是int a = 0.。

我们可以使用gdb来检查差异:

(gdb) list f1
19  {
20      int a;
21      if (x)
22          a = 42;
23      else
24          a = 0;
25      return a;
26  }
(gdb) list f2
28  int f2(int x)
29  {
30      int a = 0;
31      if (x)
32          a = 42;
33      return a;
34  }

现在让我们用-O3:

查看汇编程序代码
(gdb) disassemble f1
Dump of assembler code for function f1:
   0x00000000004007a0 <+0>: cmp    $0x1,%edi
   0x00000000004007a3 <+3>: sbb    %eax,%eax
   0x00000000004007a5 <+5>: not    %eax
   0x00000000004007a7 <+7>: and    $0x2a,%eax
   0x00000000004007aa <+10>:    retq   
End of assembler dump.
(gdb) disassemble f2
Dump of assembler code for function f2:
   0x00000000004007b0 <+0>: cmp    $0x1,%edi
   0x00000000004007b3 <+3>: sbb    %eax,%eax
   0x00000000004007b5 <+5>: not    %eax
   0x00000000004007b7 <+7>: and    $0x2a,%eax
   0x00000000004007ba <+10>:    retq   
End of assembler dump.

如你所见,没有区别。让我们用-O0:

禁用优化
(gdb) disassemble f1
Dump of assembler code for function f1:
   0x00000000004006cd <+0>: push   %rbp
   0x00000000004006ce <+1>: mov    %rsp,%rbp
   0x00000000004006d1 <+4>: mov    %edi,-0x14(%rbp)
   0x00000000004006d4 <+7>: cmpl   $0x0,-0x14(%rbp)
   0x00000000004006d8 <+11>:    je     0x4006e3 <f1+22>
   0x00000000004006da <+13>:    movl   $0x2a,-0x4(%rbp)
   0x00000000004006e1 <+20>:    jmp    0x4006ea <f1+29>
   0x00000000004006e3 <+22>:    movl   $0x0,-0x4(%rbp)
   0x00000000004006ea <+29>:    mov    -0x4(%rbp),%eax
   0x00000000004006ed <+32>:    pop    %rbp
   0x00000000004006ee <+33>:    retq   
End of assembler dump.
(gdb) disassemble f2
Dump of assembler code for function f2:
   0x00000000004006ef <+0>: push   %rbp
   0x00000000004006f0 <+1>: mov    %rsp,%rbp
   0x00000000004006f3 <+4>: mov    %edi,-0x14(%rbp)
   0x00000000004006f6 <+7>: movl   $0x0,-0x4(%rbp)
   0x00000000004006fd <+14>:    cmpl   $0x0,-0x14(%rbp)
   0x0000000000400701 <+18>:    je     0x40070a <f2+27>
   0x0000000000400703 <+20>:    movl   $0x2a,-0x4(%rbp)
   0x000000000040070a <+27>:    mov    -0x4(%rbp),%eax
   0x000000000040070d <+30>:    pop    %rbp
   0x000000000040070e <+31>:    retq   
End of assembler dump.

现在存在差异,随机参数x的平均第一个版本会更快,因为它的第一个版本比第二个版本少一个。

答案 3 :(得分:0)

如果您的第二个代码是

int f(int x) 
{
    int a=0;
    if(x)
        a = 42;
    return a; 
}

而不是

int f(int x) 
{
    int a;
    if(x)
        a = 42;
    return a; 
}

没关系。编译器会将它们转换为相同的优化代码

答案 4 :(得分:0)

我更喜欢这个(你的第二个片段):

int f(int x) {

    int a = 0;

    if (x) {
        a = 42;
    }
    return a;
}
  • 一切都应该有牙套。即使现在我在if块中只有一行,我后来添加了更多。
  • 我没有把括号放在自己的线上,因为这是毫无意义的浪费空间。
  • 我很少把这个块放在与可读性条件相同的行上。

答案 5 :(得分:0)

在任何一种情况下,你都不需要额外的空间 - 你可以做这样的事情 -

ps -eo user,pid,ppid,comm --sort start_time | head -n "$LINES"

BTW在你的第二个功能中你没有初始化a。