作者:南方的狼1975 | 来源:互联网 | 2022-11-24 18:35
在c ++ 11中,根据en.cppreference.com,
对于有符号和非负数a,如果它在返回类型中可表示,则<*2 b,否则行为未定义.
我的理解是,由于255*2 24不能表示为a int32_t
,因此对(int32_t) 255 <<24
产量的评估是未定义的行为.那是对的吗?这可能是编译器依赖的吗?这是一个IP16环境,如果重要的话.
背景:这来自我与arduino.stackexchange.com上的用户的争论.根据他的说法,"根本就没有任何不确定":
你注意到大部分的位移是"实现定义".所以你不能从规范中引用章节和经文.您必须转到GCC文档,因为这是唯一可以告诉您实际情况的地方.
gnu.org/software/gnu-c-manual/gnu-c-manual.html#Bit-Shifting - 对于负移位值,它只是"未定义".
编辑:从目前为止的答案来看,似乎我对C++ 11标准的阅读是正确的.然后我的问题的关键部分是这个表达式是否在gcc中调用未定义的行为.正如davmac在他的评论中所说,我问"GCC,一个实现,是否定义了一种行为,即使它未被语言标准定义".
从我链接到的gcc手册,看起来确实已经定义了,虽然我发现本手册的措辞听起来更像是教程而不是"语言法".从PSkocik的答案(以及Kane对该答案的评论)来看,它似乎是未定义的.所以我仍然有疑问.
我想我的梦想是在一些gcc文档中有明确的声明,说明1)gcc没有定义标准中明确未定义的任何行为,或者2)gcc确实从版本XX.XX定义了这种行为并且提交到保持在所有后续版本中定义.
编辑2:PSkocik删除了他的答案,我发现这很不幸,因为它提供了有趣的信息.根据他的回答,凯恩对答案的评论以及我自己的实验:
(int32_t)255<<24
使用clang和编译时产生运行时错误 -fsanitize=undefined
相同的代码即使使用g ++也不会产生错误
-fsanitize=undefined
(int32_t)256<<24
编译时会出现运行时错误
g++ -std=c++11 -fsanitize=undefined
第2点与C++ 11模式中gcc比标准更广泛地定义左移的解释是一致的.根据第3点,这个定义可能只是C++ 14的定义.但是,第3点
与引用的手册是gcc(C++ 11模式)的完整定义的想法不一致,因为该手册没有提供可能未定义的提示.<<
(int32_t)256<<24
1> Barry..:
随着时间的推移,这种情况发生了变化,并且有充分的理由,让我们来看看历史.请注意,在所有情况下,只需执行static_cast(255u <<24)
一直定义的行为.也许只是这样做并侧面解决所有问题.
最初的C++ 11措辞是:
值E1 <是E1
左移位E2
位置; 空位是零填充的.如果E1
具有无符号类型,则结果的值将比结果类型中可表示的最大值模数减1.否则,如果有一个有符号类型和非负值,并且在结果类型中可表示,那么这就是结果值; 否则,行为未定义.E1×2E2
E1
E1×2E2
255 <<24
是C++ 11中未定义的行为,因为结果值不能表示为32位有符号整数,它太大了.
这种未定义的行为会导致一些问题,因为constexpr
必须诊断未定义的行为 - 因此设置值的一些常用方法会导致硬错误.因此CWG 1457:
8.8 [expr.shift]第2段的当前措辞使得通过将(带符号)1左移到符号位来创建给定类型的最负整数的未定义行为,即使这并非罕见地完成并且有效正确地在大多数(二进制补码)架构上[...]因此,这种技术不能用于常量表达式,这将破坏大量代码.
这是针对C++ 11的缺陷.从技术上讲,符合标准的C++ 11编译器会实现所有缺陷报告,因此在C++ 11中说这不是未定义的行为是正确的.255 <<24
C++ 11中的行为被定义为-16777216
.
可以在C++ 14中看到缺陷后的措辞:
值E1 <是E1
左移位E2
位置; 空位是零填充的.如果E1
具有无符号类型,则结果的值将比结果类型中可表示的最大值模数减1.否则,如果具有有符号类型和非负值,并且在结果类型的相应无符号类型中可表示,则转换为结果类型的该值是结果值; 否则,行为未定义.E1×2E2
E1
E1×2E2
C++ 17中的措辞/行为没有变化.
但对于C++ 20,由于Signed Integers是Two's Complement(及其措辞文件),措辞大大简化:
值E1 <是与模数一致的唯一值,其中是结果类型的范围指数.E1×2E2
2N
N
255 <<24
仍然在C++ 20中定义了行为(具有相同的结果值),只是我们如何到达那里的规范变得更加简单,因为语言不必解决签名整数的表示形式的问题.实现定义.