if(var == true)是否比if(var!= false)更快?

非常简单的问题。 我知道这可能是一个很小的优化,但最终你会使用足够的if语句来解决它。

编辑:谢谢那些提供了答案的人。

对于那些觉得有必要打击我的人,要知道好奇心和对知识的渴望并不能转化为愚蠢。

非常感谢所有提出建设性批评的人。 到目前为止,我还不知道是否(var)。 我确定我现在会用它。 ;)

首先:回答性能问题的唯一方法是测量它 。 亲自尝试,你会发现。

至于编译器的作用:我提醒你“if”只是一个条件goto。 当你有

 if (x) Y(); else Z(); Q(); 

编译器将其生成为:

 evaluate x branch to LABEL1 if result was false call Y branch to LABEL2 LABEL1: call Z LABEL2: call Q 

要么

 evaluate !x branch to LABEL1 if result was true 

取决于是否更容易生成代码以引出“正常”或“反转”结果,无论“x”恰好是什么。 例如,如果你有if (a<=b)它可能更容易生成(if !(a>b)) 。 或相反亦然; 这取决于正在编译的确切代码的细节。

无论如何,我怀疑你有更大的鱼要炸。 如果您关心性能,请使用分析器找到最慢的东西 ,然后解决它 。 当你可能在程序中的其他地方浪费整整毫秒时,毫无意义地担心纳秒优化。

您是否知道在x86处理器上执行x ^= x更高效,其中x是32位整数,而不是x = 0 ? 这是真的,当然也有相同的结果。 因此,任何时候都可以在代码中看到x = 0 ,可以用x ^= x替换它并获得效率。

现在,你有没有看过很多代码中的x ^= x

你没有的原因不仅仅是因为效率增益很小,而是因为这正是编译器(如果编译为本机代码)或抖动(如果编译IL或类似代码)会产生的那种变化。 反汇编一些x86代码并且看到程序集等效于x ^= x并不罕见,尽管编译为执行此操作的代码几乎肯定有x = 0或者可能更复杂,如x = 4 >> 6x = 32 - y ,其中代码分析显示y将始终包含32 ,依此类推。

出于这个原因,尽管已知x ^= x更有效,但它在绝大多数情况下的唯一影响是使代码的可读性降低(唯一的例外是x ^= y在一个正在使用的算法中,我们碰巧做了一个xy在这里相同的情况,在这种情况下, x ^= x会使得该算法的使用更清晰,而x = 0会隐藏它。

在99.999999%的案例中,同样适用于您的示例。 在剩余的0.000001%的情况下,它应该但是在某些奇怪的操作符覆盖之间存在效率差异, 并且编译器无法将其中一个解析为另一个。 事实上,0.000001%是夸大案件,刚刚提到,因为我很确定,如果我努力了,我可以写一些效率低于另一个的东西。 通常人们并不努力这样做。

如果您在reflection器中查看自己的代码,您可能会发现一些与您编写的代码看起来非常不同的情况。 这样做的原因是它是对代码的IL进行逆向工程,而不是代码本身,而且你经常会发现的一件事就是if(var == true)if(var != false)转换成if(var)if(!var)ifelse块反转。

看得更深,你会发现即使是进一步的改变,也有不止一种方法可以让同一只猫皮肤。 特别是,查看switch语句转换为IL的方式很有意思; 有时候它变成了一堆if-else if语句的等价物,有时它变成了一个可以进行的跳转表的查找,这取决于在所讨论的情况下看起来更有效。

查看更深入,并在编译为本机代码时进行其他更改。

我不同意那些谈论“过早优化”的人只是因为你询问两种不同方法之间的性能差异,因为对这种差异的了解是一件好事,它只是过早地使用这种知识是不成熟的(通过定义)。 但是,即将被编译出来的变化既不是过早的,也不是优化,它只是一个零变化。

它根本不会有任何区别。 使用reflection器你可以看到代码:

 private static void testVar(bool var) { if (var == true) { Console.WriteLine("test"); } if (var != false) { Console.WriteLine("test"); } if (var) { Console.WriteLine("test"); } } 

创建IL:

 .method private hidebysig static void testVar(bool var) cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: brfalse.s L_000d L_0003: ldstr "test" L_0008: call void [mscorlib]System.Console::WriteLine(string) L_000d: ldarg.0 L_000e: brfalse.s L_001a L_0010: ldstr "test" L_0015: call void [mscorlib]System.Console::WriteLine(string) L_001a: ldarg.0 L_001b: brfalse.s L_0027 L_001d: ldstr "test" L_0022: call void [mscorlib]System.Console::WriteLine(string) L_0027: ret } 

因此编译器(在.Net 3.5中)将它们全部转换为ldarg.0,brfalse.s指令集。

它将使绝对零差异,因为编译器几乎肯定会将两个语句编译为相同的二进制代码。

(伪)程序集将是:

 test reg1, reg2 br.true somewhere ; code for false case somewhere: ; code for true case 

要么

 test reg1, reg2 br.false somewhere ; code for true case somewhere: ; code for false case 

编译器选择哪一个不取决于你是写== true还是!= false 。 相反,它是编译器根据真假案例代码的大小以及其他一些因素进行的优化。

UNLIKELY ,Linux内核代码实际上尝试使用UNLIKELYUNLIKELY宏来优化这些分支的if条件,所以我想可以手动控制它。

无论您在程序中使用多少次迭代,都不会产生任何可测量的差异。

(改用if (var) ;你不需要比较的视觉混乱。)

通常有效的经验法则是“如果你知道它们做同样的事情,那么编译器也会知道”。

如果编译器知道两个表单产生相同的结果, 那么它将选择最快的一个

因此,假设它们同样快,直到你的探查器告诉你。

始终优化以便于理解 。 就我而言,这是编程的基本规则。 知道需要这样做之前 ,您不应该进行微观优化,甚至根本不进行优化,以及您需要这样做的地方。 这是一个非常罕见的情况,挤出每一盎司的性能比可维护性更重要,你甚至更难以知道在最初编写代码时优化的位置。

此外,这样的事情会以任何体面的语言自动优化。

tl;博士不要打扰

其他答案都很好,我只想补充一下:

这不是一个有意义的问题,因为它假定符号与生成的IL或本机代码之间存在1:1的关系。

没有。 即使在C ++中,甚至在C语言中也是如此。你必须一直到本机代码才能让这样的问题有意义。

编辑添加:

第一个Fortran编译器(约1957年)的开发人员有一天在审查其输出时感到惊讶。 它发出的代码显然不正确(虽然它是); 实质上,它正在做出不明显正确的优化决策(虽然它们是)。

这个故事的寓意:50多年来,编译器比人们更聪明。 除非您准备检查其输出和/或进行广泛的性能测试,否则不要试图超越它们。

它没有任何区别,编译器可以随意交换它们。

例如,你可以写

 if (!predicate) statement1; else statement2; 

并且编译器可以自由地发出相当于的代码

 if (predicate) statement2; else statement1; 

或相反亦然。

知道这两个特定情况中的哪一个更快是一个细节级别,在高级语言中很少(如果有的话)。 如果你的编译器在优化时很糟糕,也许你可能需要知道它。 但是,如果你的编译器很糟糕,那么如果可能的话,你可能会更好地获得更好的编译器。

如果你是在汇编编程,那么你更有可能知道这两种情况会更好。 其他人已经就分支声明给出了汇编细分,所以我不打算复制响应的那一部分。 但是,我认为遗漏的一个项目是比较项目。

可以想象,处理器可以在加载’var’时改变状态标志。 如果是,那么如果’var’为0,则可以在将变量加载到寄存器中时设置零标志。 使用这样的处理器,不需要与FALSE进行明确的比较。 等效的汇编伪代码将是……

 load 'var' into register branch if zero or if not zero as appropriate 

使用这个相同的处理器,如果您要对它进行测试,那么程序集伪代码将是……

 load 'var' into register compare that register to TRUE (a specific value) branch if equal or if not equal as appropriate 

在实践中,任何处理器的行为都是这样的吗? 我不知道 – 其他人比我更了解情况。我知道有些人不会以这种方式行事,但我不知道所有人。

假设某些处理器的行为与上述场景相同,我们可以学到什么? IF(这是一个很大的IF)你会担心这一点,避免测试布尔值对显式值…

 if (var == TRUE) if (var != FALSE) 

并使用以下之一来测试布尔类型…

 if (var) if (!var)