msc*_*msc 38 c gcc bit-manipulation language-lawyer unspecified-behavior
C11§6.5.7第5段:
结果
E1 >> E2是E1右移位E2位置.如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是商的整数部分E1 / 2*^E2.如果E1具有有符号类型和负值,则结果值是实现定义的.
但是,viva64参考文档说:
Run Code Online (Sandbox Code Playgroud)int B; B = -1 >> 5; // unspecified behavior
我在GCC上运行了这个代码,它总是给出一个输出-1.
所以,标准说"如果E1有一个带符号的类型和一个负值,结果值是实现定义的",但该文档说这-1>>5;是未指定的行为.
那么,-1>>5;C中是否有未指明的行为?哪个是对的?
dbu*_*ush 39
两者都是正确的.实现定义的行为是一种特定类型的未指定行为.
引用C标准的 3.4.1节,它定义了"实现定义的行为":
1 实现定义的行为
未指定的行为,其中每个实现都记录了如何进行选择
2示例实现定义的行为的示例是当有符号整数向右移位时高阶位的传播.
从3.4.4节定义"未指明的行为":
1个 未指明的行为
使用未指明的值,或本国际标准提供两种或更多种可能性的其他行为,并且在任何情况下都不会对其进行任何进一步的要求
2示例未指定行为的示例是评估函数参数的顺序.
至于GCC,你总会得到相同的答案,因为操作是实现定义的.它通过符号扩展实现负数的右移
对有符号整数进行一些按位运算的结果(C90 6.3,C99和C11 6.5).
按位运算符作用于值的表示,包括符号和值位,其中符号位被立即考虑在最高值位之上.签名
>>通过符号扩展对负数进行处理.作为C语言的扩展,GCC不使用C99和C11中给出的宽容度来将签名的某些方面
<<视为未定义.但是,-fsanitize=shift(和-fsanitize=undefined)将诊断此类病例.它们也被诊断为需要常量表达式.
skr*_*sme 14
"未指明的行为"和"实施定义"并不矛盾.它只是意味着C标准没有规定需要发生什么,并且各种实现可以做他们认为"正确"的事情.
在一个编译器上运行多次并获得相同的结果只意味着该特定编译器是一致的.您可能会在不同的编译器上获得不同的结果.