Som*_*ame 4 c strict-aliasing unions type-punning
其中有一个关于s 和s 的6.5(p7)项目符号:unionaggregate
\n\n\n对象的存储值只能由具有以下类型之一的左值表达式访问:
\n\n[...]
\n\n\xe2\x80\x94 聚合或联合类型,在其成员中包含上述类型之一(递归地包括子聚合或包含的联合的成员),或者
\n
这句话的意思还不是很清楚。是否需要至少一个成员或所有成员满足严格的别名规则。特别是关于unions:
union aliased{\n unsigned char uint64_repr[sizeof(uint64_t)];\n uint64_t value;\n};\n\nint main(int args, const char *argv[]){\n uint64_t some_random_value = 123;\n union aliased alias;\n memcpy(&(alias.uint64_repr), &some_random_value, sizeof(uint64_t));\n printf("Value = %" PRIu64 "\\n", alias.value);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n程序的行为是否明确定义?如果不是,那子弹是什么意思?
\n这意味着使用 aunion是一种符合标准的方法,可以避免类型双关和严格的别名冲突,否则如果您尝试通过不同类型的指针访问存储的值,则会发生严格的别名冲突。
以 和 为例unsigned,float通常都是 32 位,在某些情况下可能需要从unsigned*或 中查看存储的值。float*例如,您不能这样做:
float f = 3.3;
// unsigned u = *(unsigned *)&f; /* violation */
Run Code Online (Sandbox Code Playgroud)
遵循6.5(p7),您可以union在两种类型之间使用 a 并访问相同的信息,无论unsigned是否float对指针进行类型双关或违反严格的别名规则,例如
typedef union {
float f;
unsigned u;
} f2u;
...
float f = 3.3;
// unsigned u = *(unsigned *)&f; /* violation */
f2u fu = { .f = f };
unsigned u = fu.u; /* OK - no violation */
Run Code Online (Sandbox Code Playgroud)
因此,严格的别名规则阻止通过另一种类型的指针访问有效类型的内存,除非该指针是char类型或指向两种类型之间的联合成员的指针。
(注意:标准的这一部分根本不是一个清晰的例子。(你可以读 10 遍,但仍然摸不着头脑)它的目的是遏制指针类型的滥用,同时仍然认识到指针类型的块任何形式的内存都必须能够通过字符类型访问(并且 aunion是其他允许的访问方式之一)。
过去几年,编译器在标记违反规则方面已经做得更好了。