通过工会别名

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
\n\n

这句话的意思还不是很清楚。是否需要至少一个成员所有成员满足严格的别名规则。特别是关于unions:

\n\n
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}\n
Run Code Online (Sandbox Code Playgroud)\n\n

演示版

\n\n

程序的行为是否明确定义?如果不是,那子弹是什么意思?

\n

Dav*_*ica 5

这意味着使用 aunion是一种符合标准的方法,可以避免类型双关和严格的别名冲突,否则如果您尝试通过不同类型的指针访问存储的值,则会发生严格的别名冲突。

以 和 为例unsignedfloat通常都是 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是其他允许的访问方式之一)。

过去几年,编译器在标记违反规则方面已经做得更好了。

  • 是的,答案是代码定义良好。在很多情况下,您只是通过另一种类型(或者如果类比有帮助的话,通过另一个窗口)“查看数据”。使用指针查看另一个指针的数据,虽然从技术上讲是一种违规行为,但取决于操作方式,很少会产生任何后果。它使用不同类型的指针来尝试修改由于类型大小或填充不匹配而导致损坏/未定义行为的最大风险的地方。在这种情况下,不值得去尝试命运。 (3认同)