是这个:
int val;
// ...
val = (val != 0) ? otherVal : 0;
效率低于此:
int val;
//...
if (val != 0)
val = otherVal;
?
编译器是否能够优化三元运算符?目的很明确,实际上有什么方法可以将0写入内存吗?也许当内存映射到文件时?
我们可以认为这没关系吗?
编辑:关键是如果满足一个条件,则将变量设置为某个值。没有想要的其他分支。这就是为什么我问三元(带有强制性的else分支,应该复制)的效率或优化程度较低的原因。
Mats Petersson的建议通常是最好的“写出最具可读性的变体”。但是,if试图编写最佳速度性能代码,则需要了解有关计算机和处理器的更多信息。对于某些机器,第一个会运行得更快(高度流水线处理器:无分支,优化的三元运算符)。使用第二种形式(更简单),其他计算机将更快地运行。
您的编译器将对其进行优化。最后,性能几乎没有差异。
但是,可读性有很大差异。有时,三元运算符可以帮助删除很多不太清晰的代码行。
在其他情况下,if
语句更清晰,更易于遵循。
将代码简化为三元语句,但随后为了保持清晰性而不得不添加大量注释会适得其反。
而且所有编码之神,请不要嵌套三元语句。
您可以使用无分支三元运算符,有时也称为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);
}
这主要是Ternary operator ?: vs if...else的副本
对于大多数编译器,效率是相同的,并且编译器将优化三元运算符,就像优化if / else语句一样。就是说,我更喜欢if语句,因为它们使代码更容易快速浏览。
回答您的其他问题。我不确定您的意思,如果您只是将一个整数或变量设置为0,那么除了像上面一样将其设置为零之外,没有别的更快的方法。
如果您有一个变量数组,则可以使用memset(ptr, 0, size*sizeof(TYPE))
,如果您有一个要设置为零的变量数组,这可能是最快的。也许std :: fill_n
我不确定您要使用上述逻辑实现什么,但似乎有些奇怪。有一些方法可以安排代码,这意味着您可能根本不需要条件代码,但是如果看不到更多代码,很难说出您的情况。
老实说,除非您进行数十亿次此操作,否则这可能是非常过早的优化,您应该专注于可读性。
诸如“编译器资源管理器”之类的工具非常擅长回答此类问题。修复代码和comparing the following two snippets中的错误,我们看到它们在-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