4 c bit-shift bit compiler-optimization
我想要指出的是,正如Olaf所指出的,编译器没有错.
免责声明:我不完全确定这种行为是由编译器优化引起的.
不管怎么说,在C我试图一个8位字节,以确定是否第n位(n应在0和7之间,包括端点)是1或0.我最初想出了这个解决方案:
#include <stdint.h>
#include <stdbool.h>
bool one_or_zero( uint8_t t, uint8_t n ) // t is some byte, n signifies which bit
{
return (t << (n - (n % 8) - 1)) >> 7;
}
Run Code Online (Sandbox Code Playgroud)
根据我之前的理解,这将对字节执行以下操作:
假设t = 5和n = 2.然后该字节t可以表示为0000 0101.我认为(t << (n - (n % 8) - 1))会的位移位t,这样t是1010 0000.这个假设只是有些正确.我还假设下一个比特移位(>> 7)将比特移位的t,从而t是0000 0001.这个假设也只是有些正确.
TL; DR:我认为这条线return (t << (n - (n % 8) - 1)) >> 7;是这样做的:
t 是 0000 0101t就是现在1010 0000t就是现在0000 0001t 作为返回 0000 0001虽然我打算这样做,但事实并非如此.相反,我必须写下以下内容,以获得我的预期结果:
bool one_or_zero( uint8_t t, uint8_t n ) // t is some byte, n signifies which bit
{
uint8_t val = (t << (n - (n % 8) - 1));
return val >> 7;
}
Run Code Online (Sandbox Code Playgroud)
我知道添加uint8_t val不是一个巨大的性能消耗.不过,我想知道两件事:
我的印象是,当编译器优化我的代码时,它会将两个位移一起打破,所以只发生一个.这似乎是一件好事,但它没有按照预期"清除"其他位.
该代码非常复杂,只需检查一个整数位.尝试标准方法:
return (t & (1U << n)) != 0;
Run Code Online (Sandbox Code Playgroud)
如果必须检查n是否有效,请添加断言.否则掩蔽(n & 7)或模数(n % 8)(这将由编译器优化到掩码操作)将强制移位计数在有效范围内.由于该模式将被许多编译器识别,因此如果可用,它们可能会将其转换为单个位测试CPU指令.
为了避免幻数,你应该用以下方法替换模数8:(sizeof(t) * CHAR_BIT).这将遵循任何类型t可能具有的.掩模总是小于模数.
你的代码:
(n - (n % 8) - 1))
Run Code Online (Sandbox Code Playgroud)
如果n < 8它产生负值(-1精确地).负向变化呈现未定义的行为,因此任何事情都可能发生(注意鼻子恶魔).