Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 三元运算符vs if语句:编译器优化_C++_C_Optimization_Ternary Operator - Fatal编程技术网

C++ 三元运算符vs if语句:编译器优化

C++ 三元运算符vs if语句:编译器优化,c++,c,optimization,ternary-operator,C++,C,Optimization,Ternary Operator,这是: int val; // ... val = (val != 0) ? otherVal : 0; 效率低于此: int val; //... if (val != 0) val = otherVal; ? 编译器是否能够优化三元运算符?意图很清楚,是否有任何方法可以将0写入内存?也许当内存映射到文件时 我们能假设这不重要吗 编辑:要点是在满足一个条件的情况下将变量设置为某个值。没有其他的分支。这就是为什么我问一个三元结构(带有必须复制的else分支)是否效率较低或优化。您

这是:

int val;  
// ...
val = (val != 0) ? otherVal : 0;
效率低于此:

int val;
//...
if (val != 0)
    val = otherVal;
?

编译器是否能够优化三元运算符?意图很清楚,是否有任何方法可以将0写入内存?也许当内存映射到文件时

我们能假设这不重要吗


编辑:要点是在满足一个条件的情况下将变量设置为某个值。没有其他的分支。这就是为什么我问一个三元结构(带有必须复制的else分支)是否效率较低或优化。

您的编译器将对其进行优化。最后,性能几乎没有差别

然而,在可读性方面有很大的不同。有时,三元运算符可以帮助删除许多不太清晰的代码行

在其他情况下,
if
语句更清晰,更容易理解

将代码简化为三元语句,但为了保持清晰性而不得不添加大量注释,这会适得其反


所有的编码之神都说,请不要嵌套三元语句。

这主要是对

对于大多数编译器来说,效率是相同的,编译器将优化三元运算符,就像它优化if/else语句一样。也就是说,我更喜欢if语句,因为它们使代码更易于快速阅读

回答你的其他问题。我不确定你的意思,如果你只是将一个整数或变量设置为0,那么除了像上面那样将其设置为0之外,没有其他更快的方法

如果您有一个变量数组,可以使用
memset(ptr,0,size*sizeof(TYPE))
,如果您有一个要设置为零的变量数组,这可能是最快的。或者std::fill\n

我不确定你想用上面的逻辑实现什么,但这似乎有点奇怪。有一些方法可以安排代码,这意味着您可能根本不需要一个条件,但是如果不看到更多的代码,很难说您的情况


老实说,除非你做了几十亿次这个操作,否则这可能是非常早熟的优化,你应该专注于可读性。

Mats-Peterson的建议通常是最好的“编写最可读的变体”。
但是,如果您试图编写最佳速度性能代码,则需要了解有关计算机和处理器的更多信息。对于某些机器,第一台运行得更快(高度流水线处理器:无分支、优化的三值运算符)。其他机器使用第二种形式(更简单)运行得更快。

您可以使用无分支三值运算符,有时称为bitselect(条件?true:false)

不要担心额外的操作,与if语句分支相比,它们算不了什么

比特选择实现:

inline static int bitselect(int condition, int truereturnvalue, int falsereturnvalue)
{
    return (truereturnvalue & -condition) | (falsereturnvalue & ~(-condition)); //a when TRUE and b when FALSE
}

inline static float bitselect(int condition, float truereturnvalue, float falsereturnvalue)
{
    //Reinterpret floats. Would work because it's just a bit select, no matter the actual value
    int& at = reinterpret_cast<int&>(truereturnvalue);
    int& af = reinterpret_cast<int&>(falsereturnvalue);
    int res = (at & -condition) | (af & ~(-condition)); //a when TRUE and b when FALSE
    return  reinterpret_cast<float&>(res);
}
内联静态int位选择(int条件、int truereturnvalue、int falsereturnvalue)
{
return(truereturnvalue&-condition)|(FALSE returnvalue&~(-condition));//a为真,b为假
}
内联静态浮点位选择(int条件、浮点truereturnvalue、浮点FalsReturnValue)
{
//重新解释浮动。会起作用,因为它只是一个选择,不管实际值如何
int&at=重新解释(truereturnvalue);
int&af=重新解释(falsereturnvalue);
int res=(at&-condition)|(af&~(-condition));//a为真,b为假
返回重新解释(res);
}
像“编译器资源管理器”这样的工具非常擅长回答这样的问题。修复了代码中的错误,我们看到它们在-O1和更高级别生成相同的程序集

void trinary(int& val, int otherVal) {
    val = (val != 0) ? otherVal : 0;
}

void nontrinary(int& val, int otherVal) {
    if(val != 0) {
        val = otherVal;
    }
    else {
        val = 0;
    }
}

trinary(int&, int):
        mov     eax, DWORD PTR [rdi]
        test    eax, eax
        mov     eax, 0
        cmove   esi, eax
        mov     DWORD PTR [rdi], esi
        ret
nontrinary(int&, int):
        mov     eax, DWORD PTR [rdi]
        test    eax, eax
        mov     eax, 0
        cmove   esi, eax
        mov     DWORD PTR [rdi], esi
        ret
有趣的是,在-O0时,它们不会产生相同的输出。在-O0处,编译器使用
eax
显式存储三元运算符的结果,然后在返回之前将
eax
复制到正确的寄存器中。非三元版本直接执行赋值

trinary(int&, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        test    eax, eax
        je      .L2
        mov     eax, DWORD PTR [rbp-12]
        jmp     .L3
.L2:
        mov     eax, 0
.L3:
        mov     rdx, QWORD PTR [rbp-8]
        mov     DWORD PTR [rdx], eax
        nop
        pop     rbp
        ret
nontrinary(int&, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        test    eax, eax
        je      .L5
        mov     rax, QWORD PTR [rbp-8]
        mov     edx, DWORD PTR [rbp-12]
        mov     DWORD PTR [rax], edx
        jmp     .L7
.L5:
        mov     rax, QWORD PTR [rbp-8]
        mov     DWORD PTR [rax], 0
.L7:
        nop
        pop     rbp
        ret

Duplicit问题:我不是一个编译器程序员,所以我真的不知道,但它可能会计算三元运算符的两边,从而跳过分支(这会使它变得很快)。如果有任何问题,val在已经为零时设置为0,这在第一种情况下是不必要的。编译器不太可能做任何不同的事情。编写可读性最高的变量。@Hassedev否,
?:
条件运算符不允许同时计算其两个参数。@unwind Ok,感谢您的澄清。我记得它确实评估了GLSL的两个方面,但是不知道它对CPU和C++的作用。C++中你可以想象拷贝分配的发生。例如:“对象a=对象(默认);a=(条件)?对象(变量):对象(默认)”。编译器是否足够聪明和积极,足以删除赋值?听起来很危险,因为在构造函数中可能会发生一些事情。对于普通的旧数据会有什么不同吗?“不要嵌套三元语句”。。。除非您别无选择(
constexpr
),否则有一种称为“复制省略”的优化,允许编译器防止一些不必要的复制。我认为对象(…)永远不会被构建,因为它是一个无名的temp,并且被分配给一个变量。只是想了解可读性对性能的影响。在某些情况下,使用三元可能会提高可读性,但也会导致性能成本。这意味着if赋值在逻辑上会更快,但如果我想使用三元来提高可读性,我会反对这种简单的逻辑。如果我这样做,编译器能优化它吗?很明显,三元else分支对于PoD是无用的。但同样,当文件映射到内存或对驱动程序进行编程时,每次写入内存都会产生影响。。。我需要了解大多数编译器在这方面是如何工作的。大多数编译器都会优化ternar