一个普通的`char`类型能够有陷阱值吗?

24

README

“陷阱值”或“陷阱表示”是指类型T的底层存储的一种位组合,它产生了一个无效的T值。尝试解释无效值的表示将导致“未定义行为”。


让战斗开始..

又有一个问题引发了有关char以及其可能具有陷阱表示的激烈讨论。

问题

  • char是否可能具有陷阱值?

在先前的讨论中提到的引用:

这些部分是先前争论中最常引用的部分,它们是否相互矛盾?

3.9.1p1 基本类型 [basic.fundamental]

实现定义了char是否可以持有负值。字符可以明确声明为signedunsigned

charsigned charunsigned char占用相同的存储空间,并具有相同的对齐要求(3.11);也就是说,它们具有相同的对象表示。对于字符类型,对象表示的所有位都参与值表示。

对于无符号字符类型,值表示的所有可能位模式都表示数字。这些要求不适用于其他类型。

在任何特定实现中,普通的char对象可以采用与signed charunsigned char相同的值;哪一个是实现定义的。

3.9p2 类型 [basic.types]

对于任何平凡可复制类型T的对象(除了基类子对象),无论对象是否持有类型T的有效值,组成对象的底层字节(1.7)都可以复制到charunsigned char数组中。

如果将charunsigned char数组的内容复制回对象,则对象随后应保持其原始值。


陷阱值:https://dev59.com/jWw15IYBdhLWcg3wQ5hi#6725981 - QuestionC
根据C++11标准,“分配给寄存器的未确定值的无符号char对象可能会陷阱。” - 如果是这种情况,那么我希望charsigned char也是如此。 - Tony Delroy
Filip,我们能否将AddressSanitizer / MemorySanitizer(现代LLVM和GCC中的可选功能)视为确认语言实现?Sanitizers会向每个内存单词添加一些标签(存储在单独的内存中,模拟苏联Elbrus架构标签,在一些大型Burroughs中存在类似的想法),并且对于某些标签值会出现陷阱,例如,读取未初始化的内存。 - osgx
C++11标准还明确列出了对于“unsigned”、“signed”和“未指定”的char的numeric_limits<>特化,而且还有一个static constexpr bool traps成员,这样你就可以在编译时检查、断言等。 - Tony Delroy
能否请给出负分的投票者解释一下为什么这个问题会吸引到-1的评分呢? - Filip Roséen - refp
1个回答

5
标准要求如下:
  • char、signed char、unsigned char 必须相同大小
  • sizeof(char) 应该是1
  • char 至少应该有8个位
  • 每一个比特组合都是有意义并且有效的
  • char 数组是紧凑的(或者被视为是紧凑的)
没有太多的余地。但是在某些操作期间,例如加载未初始化内存或转换时可能会出现陷阱。
我认为一种实现方式可以存在一个陷阱表示,其中陷阱值可能会由某些未定义或不确定行为的结果产生,包括评估涉及未指定/未初始化值的表达式。导致陷阱值的实际比特模式对于实现来说是不可见的。
这样的 CPU 可以具有9位字节,其中只有 8 位对编译器和运行时可见,第 9 位用于检测未初始化内存,并在被(非特权)指令加载时触发陷阱。

AddressSanitizer是一个CPU的软件模拟器,它为每个内存地址添加了额外的标记位。 - osgx
2
@osgx:是的,我也这么想。我曾经在伯勒斯大型系统上工作过,它标记的是单词而不是字符。在一个标记体系结构中,这种陷阱值对我来说似乎是可能的。 - david.pfx
1
最初的IBM PC确实有9位字节,其中只有8位通常可供CPU使用;内存存储器通常会将第9位写入作为其他8位的奇偶校验位,而内存读取通常会触发一个不可屏蔽中断,如果第9位与其他8位的奇偶校验不匹配,但据我所知,还有一些很少使用的诊断寄存器可以改变这种行为。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接