C 条件位设置
根据我的小型研究,以下两个函数是等效的(从性能角度来看),因为即使是非常轻微的优化(C 条件位设置,c,security,optimization,conditional,C,Security,Optimization,Conditional,根据我的小型研究,以下两个函数是等效的(从性能角度来看),因为即使是非常轻微的优化(-O1)也会产生相同的汇编代码 代码1: #define BIT_N (10) extern unsigned int isBitSet; unsigned int Foo() { unsigned int res1 = 0; if (isBitSet) { res1 |= ( 1u << BIT_N ); } return res1;
-O1
)也会产生相同的汇编代码
代码1:
#define BIT_N (10)
extern unsigned int isBitSet;
unsigned int Foo() {
unsigned int res1 = 0;
if (isBitSet)
{
res1 |= ( 1u << BIT_N );
}
return res1;
}
我个人更喜欢代码2的C版本,它看起来更干净。但它是否和代码1一样安全?因为我看到了一些潜在的陷阱,比如如果
isBitSet
的类型是int
和BIT\N
31,那么代码res1=(!!isBitSet)运算符返回的类型是int
,所以可以得到UB。(isBitSet
类型的签名性并不重要)
根据N1570,6.5.7位移位运算符:
E1的结果(值为0
或1
)。后续的。例如,假设一个32位int
和两个补码,如果!!isBitSet==1
和位N>=31
(因为随后1位被移入或移出符号位),就会发生这种情况.因此,你提到的潜在陷阱确实是一个
除此之外,代码定义良好,两个函数具有相同的行为。因此,只要避免上述未定义行为的条件,第二个函数就相当于第一个函数
也就是说,第一种可能更可取,因为它更明确地表达了它的意图(因此更容易阅读),并且不可能有未定义的行为
因为我看到了一些潜在的陷阱,比如isBitSet的类型是int和BIT_N 31
您已经遇到了另一个陷阱,即假定的类型是位集
重要的。C中的所有“逻辑”运算符,如!
都返回值为1或0的类型int
因此表达式(!!isBitSet)如果开始时res1=5
,“代码1和代码2的反汇编是相同的”。如果是,则编译器已损坏。代码1使用|=
,代码2使用=
@JeremyP,但不会更改结果。+请参阅我对的注释tilz0R@JeremyP我修改了代码,使其具有相同的|=
。但这并不是本文的重点。我发现if(isBitSet)
比(.ISBITSET)。你应该考虑让人们读代码比编译器更容易(这似乎是无论如何得到的)。<代码> ISBITSET >的类型并不重要。
#define BIT_N (10)
extern unsigned int isBitSet;
unsigned int Foo() {
unsigned int res1 = 0;
res1 |= ( (!!isBitSet) << BIT_N );
return res1;
}
Foo():
mov edx, DWORD PTR isBitSet[rip]
xor eax, eax
test edx, edx
setne al
sal eax, 10
ret
res1 |= (unsigned)(!!isBitSet) << BIT_N;
((!!isBitSet) << BIT_N) + UINT16_C(something)
uint32_t Foo (void)
{
uint32_t result;
if(isBitSet)
{
result = 1u << BIT_N;
}
else
{
result = 0;
}
return result;
}
uint32_t Foo (void)
{
return isBitSet ? 1u<<BIT_N : 0;
}