14赞
337
当前位置:  开发笔记 > 编程语言 > 正文

在gcc(C++11)中是(int32_t)255<<24未定义的行为吗?

如何解决《在gcc(C++11)中是(int32_t)255<<24未定义的行为吗?》经验,为你挑选了1个好方法。

在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×2E2E1E1×2E2

255 <<24 是C++ 11中未定义的行为,因为结果值不能表示为32位有符号整数,它太大了.

这种未定义的行为会导致一些问题,因为constexpr 必须诊断未定义的行为 - 因此设置值的一些常用方法会导致硬错误.因此CWG 1457:

8.8 [expr.shift]第2段的当前措辞使得通过将(带符号)1左移到符号位来创建给定类型的最负整数的未定义行为,即使这并非罕见地完成并且有效正确地在大多数(二进制补码)架构上[...]因此,这种技术不能用于常量表达式,这将破坏大量代码.

这是针对C++ 11的缺陷.从技术上讲,符合标准的C++ 11编译器会实现所有缺陷报告,因此在C++ 11中说这不是未定义的行为是正确的.255 <<24C++ 11中的行为被定义为-16777216.

可以在C++ 14中看到缺陷后的措辞:

E1 <E1左移位E2位置; 空位是零填充的.如果E1具有无符号类型,则结果的值将比结果类型中可表示的最大值模数减1.否则,如果具有有符号类型和非负值,并且结果类型的相应无符号类型中可表示,则转换为结果类型的该值是结果值; 否则,行为未定义.E1×2E2E1E1×2E2

C++ 17中的措辞/行为没有变化.

但对于C++ 20,由于Signed Integers是Two's Complement(及其措辞文件),措辞大大简化:

E1 <是与模数一致的唯一值,其中是结果类型的范围指数.E1×2E22NN

255 <<24 仍然在C++ 20中定义了行为(具有相同的结果值),只是我们如何到达那里的规范变得更加简单,因为语言不必解决签名整数的表示形式的问题.实现定义.

推荐阅读
devbox
南方的狼1975
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved PHP1.CN 第一PHP社区 版权所有 京ICP备19059560号-4