简单的代码片段:
#define FOO 7
int bar = -875;
bar <<= FOO;UBSAN报告称这是UB。
我的理解是,-875 << 7只是-(875<<7),没有溢出。
那么,这里真的有问题吗?
发布于 2016-04-20 17:55:13
你的理解是错误的。
首先您使用了bar <<= FOO语法。这显式地改变了bar,而bar是负的。负值的左移在C中产生未定义的行为,bar <<= FOO不可能被解释为-(875<<7)。
第二,关于-875 << 7,在算子优先级方面:一元算子总是比二进制算子具有更高的优先级,这意味着-875 << 7是(-875) << 7而不是-(875 << 7)。同样,负值的左移在C中会产生未定义的行为。
发布于 2016-04-20 18:56:01
在一个符号大小的机器上,不清楚左移负数的效果应该是什么,如果尝试这样的操作,这样的机器陷入陷阱也不是不合理的。在这样的机器上,对负整数左移的行为施加任何要求,很可能需要编译器为这些机器生成额外的代码,即使在要转移的值总是为正的情况下。为了避免强加这样的成本,标准的作者拒绝强制执行任何特定的行为。
当转移负值时,1‘-补码平台和两个补码平台将没有逻辑上的理由(虽然-1<<1应该在一个1’-补码机上产生-2还是-3 ),但是标准的作者认为没有理由说负值的左移在使用符号大小整数的平台上有未定义的行为,在使用一个补的平台上实现定义的行为,以及在使用两个补码的平台上标准定义的行为,因为任何两个补实现都会将-1<<1视为产生-2,而不管标准是否要求它,除非提交人故意迟钝。
直到2005年左右,代码还没有什么可以想象的不安全之处,这些代码只会被要求使用负值的左移位操作符在普通的二代补码机器上运行。不幸的是,大约在那个时候,一个想法开始流行起来,这表明一个编译器避免做标准没有规定的任何事情,比在标准没有授权的情况下有效的编译器更“高效”,并且这样的“效率”是可取的。我还不知道编译器认为y=x<<1;语句是追溯性地使x值为非负值,但我认为没有任何理由相信他们将来不会这样做,除非或直到某个机构正式编纂了主流微机C编译器在25+年一致支持的行为保证,这样的代码不能被认为是“安全的”。
https://stackoverflow.com/questions/36751538
复制相似问题