_Bool类型和严格别名

Lun*_*din 7 c boolean strict-aliasing language-lawyer c11

我正在尝试编写一些用于类型安全使用的宏_Bool,然后对我的代码进行压力测试.出于恶意测试的目的,我想出了这个肮脏的黑客:

_Bool b=0;
*(unsigned char*)&b = 42;
Run Code Online (Sandbox Code Playgroud)

鉴于实现上_Bool有1个字节sizeof(_Bool)==1,我不知道这个hack是如何违反C标准的.它不应该是严格的别名违规.

然而,当通过各种编译器运行此程序时,我遇到了问题:

#include <stdio.h>

int main(void)
{
  _Static_assert(sizeof(_Bool)==1, "_Bool is not 1 byte");

  _Bool b=0;
  *(unsigned char*)&b = 42;
  printf("%d ", b);
  printf("%d", b!=0 );

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

(代码依赖于printf隐式默认参数提升int)

某些版本的gcc和clang给出输出42 42,其他版本给出0 0.即使禁用了优化.我原以为是42 1.

似乎编译器假设_Bool只能是1或者0同时它42在第一种情况下快乐地打印.

Q1:这是为什么?上面的代码是否包含未定义的行为?

Q2:可靠性如何sizeof(_Bool)?C17 6.5.3.4完全没有提及_Bool.

小智 8

Q1:这是为什么?上面的代码是否包含未定义的行为?

是的,它确实.该商店是有效的,但随后阅读,因为_Bool不是.

6.2.6类型的表示

6.2.6.1总则

5某些对象表示不需要表示对象类型的值.如果对象的存储值具有这样的表示并且由不具有字符类型的左值表达式读取,则行为是未定义的.[...]

Q2:可靠性如何sizeof(_Bool)?C17 6.5.3.4完全没有提及_Bool.

它将可靠地告诉您存储一个所需的字节数_Bool.6.5.3.4也没提int,但你不是在问是否sizeof(int)可靠,是吗?

  • @KamilCuk据我所知,是的,这完全有效. (2认同)
  • @Lundin`no_trap_t no_trap = {b};`仍然无效,因为它读取陷阱表示.p6的含义是,如果它是有效的(或者如果你在结构成员中以某种其他方式获得陷阱表示),那么执行`no_trap = no_trap;`也是有效的:即使它复制了一个具有陷阱表示的成员,整个结构没有. (2认同)
  • @Lundin:保证结构体或联合体永远不是陷阱表示的目的本质上是说,如果结构体不存在可能导致的位模式,编译器只能将结构体赋值替换为逐个成员赋值此类操作有副作用。如果结构成员持有一个位模式,它是陷阱表示或与任何其他人共享其含义,我认为标准允许目标结构的相应成员持有任何等效的位模式(或任何模式,如果源是陷阱代表)。 (2认同)