【问题标题】:Would VS2008 c++ compiler optimize the following if statement?VS2008 c++ 编译器会优化以下 if 语句吗?
【发布时间】:2010-12-27 01:30:25
【问题描述】:
if (false == x) { ...}

相对于:

if (!x) { ... }

if (false == f1()) { ...}

相对于:

if (!f1()) { ... }

我认为 if(false == ... 版本更具可读性。您同意吗,或者您有其他可以提出的技巧吗?会一样快吗?谢谢。

这就是我不喜欢 !x 的原因:

if (25 == a->function1(12345, 6789) &&
    45 == b->function1(12345, 6789) &&
    !c->someOtherFunction(123)) { ... }

以下似乎更好:

if (25 == a->function1(12345, 6789) &&
    45 == b->function1(12345, 6789) &&
    false == c->someOtherFunction(123)) { ... }

【问题讨论】:

  • 呃,你为什么不看看编译器的输出呢?无论如何,在 99.9999% 的情况下,这都无关紧要。
  • @lpthnc - 因为你提到了代码审查,所以你正在与一个团队合作。我建议使用其他人使用的相同样式。即使现在您发现该样式的可读性较差,您在阅读其他团队成员的代码时也需要处理它。此外,一旦你使用有规律的样式,它就会变得非常可读。
  • 如果你想知道你的编译器做了什么,你需要研究编译器的输出,而不是问SO。 SO 仅用于从其他程序员那里获取信息。
  • 只要用C++编译器编译,然后在windbg下运行,看看生成的汇编代码。
  • 呜呜呜,为什么你的常数在左边? :P 你不是说“如果这是假的”,而是说“如果这是假的”。

标签: c++ optimization compiler-construction coding-style code-readability


【解决方案1】:

C++ 在左侧保留以下关键字作为右侧运算符的替代:

and  and_eq  bitand    &&  &=  &
or   or_eq   bitor     ||  |=  |
     xor_eq  xor           ^=  ^
not  not_eq  compl     !   !=  ~

如果您担心! 迷路,not 会更加突出。

if (    a->function1(12345, 6789) == 25 and
        b->function1(12345, 6789) == 45 and
        not c->someOtherFunction(123)) {
    ...
}

【讨论】:

【解决方案2】:

我认为 if(false == ... 版本更具可读性。你同意吗,或者你可以提出另一个技巧?

你做错了。

false == x 返回一个布尔值,显然必须与true 进行比较!

if (true == (false == x)) { ...} 会更好。但这又返回一个布尔值,所以为了安全起见,让你的代码更具可读性,我们最好这样做:

if (true == (true == (false == x))) { ...}。等等。一旦你开始比较布尔值和布尔值,你会在哪里停下来?结果将始终是另一个布尔值,为了保持一致,您必须将其与布尔值进行比较。

或者你可以学习理解你所使用的语言,并使用if (!x) { ...},它准确地表达了你想要的。

你觉得哪个更易读?

  • if (false == x) { ...} 翻译为“如果为真则假等于 x”。
  • if (!x) { ...} 翻译为“如果 x 不为真”。

你能说实话,认真,真的说第一种形式“更具可读性”吗?你会在一句话中这么说吗? “如果为真则假等于x”?

它并不更具可读性,它只是对任何阅读您的代码的程序员大喊“我不理解 if 语句或布尔值”。

【讨论】:

  • +1 for the reductio ad absurdum (crikey,我希望我拼写正确),尤其是逻辑端点:如果它是真的它是真的它是真的......它是真的x 是假的。
  • 可爱的论据。 +1 这都是关于!几乎看不见的字符。正如 ' 是用作评论的坏字符一样, !是用于“不”的坏字符。在 Python 中我可以写: if not k in dict.我希望 C++ 具有同样的可读性。
  • 我从来没有发现它不引人注意。如果您愿意,可以用空格分隔 (if ( ! x))。或者使用not 关键字代替!。它不常用(因此可能会使一些阅读您的代码的程序员感到困惑),但它是标准 C++ 的一部分。
【解决方案3】:

这是一个过早优化的案例 (When is optimisation premature?)。但是编译器会生成同样的代码(MSVC 2008 Debug模式):

if (!bVal)
    bVal = true;

if (bVal == false)
    bVal = true;

//translates to

; 70   :         if (!bVal)

cmp BYTE PTR $T5793[ebp], 0
jne SHORT $LN9@wmain
push    OFFSET $LN10@wmain
call    __RTC_UninitUse
add esp, 4
$LN9@wmain:
movzx   eax, BYTE PTR _bVal$[ebp]
test    eax, eax
jne SHORT $LN2@wmain

; 71   :             bVal = true;

mov BYTE PTR $T5793[ebp], 1
mov BYTE PTR _bVal$[ebp], 1
$LN2@wmain:

; 72   :         
; 73   :         if (bVal == false)

cmp BYTE PTR $T5793[ebp], 0
jne SHORT $LN11@wmain
push    OFFSET $LN10@wmain
call    __RTC_UninitUse
add esp, 4
$LN11@wmain:
movzx   eax, BYTE PTR _bVal$[ebp]
test    eax, eax
jne SHORT $LN1@wmain

; 74   :             bVal = true;

mov BYTE PTR $T5793[ebp], 1
mov BYTE PTR _bVal$[ebp], 1

【讨论】:

    【解决方案4】:

    一个好的编译器应该为两个代码块生成相同的代码。

    但是,与其担心 false == f1()!f1(),您应该更担心此示例中的短路评估:

    if (25 == a->function1(12345, 6789) &&
        45 == b->function1(12345, 6789) &&
        !c->someOtherFunction(123)) { ... }
    

    如果 a->function1() 调用恰好计算出不同于 25 的值,某些编译器将生成将跳过执行 b->function1()c->someOtherFunction() 的代码 - 原因是,编译器已经知道整个 @ 的结果987654327@ 语句,所以它可以跳到正确的地方。

    如果您的代码依赖于被任何跳过的函数修改的状态,您可能会遇到令人讨厌的意外。

    【讨论】:

    • 实际上,C++ 标准要求 && 运算符短路。
    • 谢谢。关于短路......我没有遇到任何没有这种知识根深蒂固的付费程序员。你有吗?
    • 比利:+1;但是,仅当使用内置 && 时,如果您已为 UDT 重载它,则它不得短路。 (是的,出于这个原因,这样做几乎总是 100% 邪恶。)
    • 大声笑,如果你知道你不应该这样做,为什么还要在里面放那个示例代码呢?
    • @Ipthns - 当然,你有点忘记,一年后新的大学毕业生会去改变这个函数来更新一些内部状态,一半的测试会失败。 :-) 在短路代码中使用函数会对该函数提出非直观且难以发现的要求。同时,这里有一些合法函数的例子,它们返回一个需要检查和修改状态的值 - InterlockExchange()、AddRef()/Release()、LoadLibrary()
    【解决方案5】:

    我个人认为if (!x) { ... } 格式最易读,但现在它们都将产生相同的代码。

    编辑:在您的示例中,我将执行以下操作:

    if (  a->function1(12345, 6789) == 25 &&
          b->function1(12345, 6789) == 45 &&
        !(c->someOtherFunction(123))) { ... }
    

    但这真的只是个人喜好。做对你来说最易读的事情。这不会有任何区别。

    【讨论】:

    • +1。 “if (n == true)”范式是一个可怕的怪物:-)
    • 现在编译器会处理这一切,有比单纯根据语法担心一行代码的速度要好得多的事情
    • 谢谢。请检查修订后的问题的可读性。
    【解决方案6】:

    您是否已分析并发现评估条件是热点?如果没有,那么按照您的编码标准要求做任何事情。

    无论如何,两者都应该编译成相同的代码。您可以通过检查编译器生成的汇编代码来检查这两种情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 2017-06-16
      • 1970-01-01
      相关资源
      最近更新 更多