Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用union在C中实现类型双关_C_Language Lawyer_Union_Type Punning - Fatal编程技术网

使用union在C中实现类型双关

使用union在C中实现类型双关,c,language-lawyer,union,type-punning,C,Language Lawyer,Union,Type Punning,考虑以下代码: union u{ int i; long j[2]; }; int main(void){ union u *u = malloc(sizeof *u); u->i = 10; printf("%li\n", u->j[0]); } 我想用6.5解释代码的合法性: 对象的存储值只能由左值访问 具有以下类型之一的表达式: -与对象的有效类型兼容的类型 [……] -一个 包含上述类型之一的聚合或联合类型 在其成员中(递归地包括子

考虑以下代码:

union u{
    int i;
    long j[2];
};

int main(void){
    union u *u = malloc(sizeof *u);
    u->i = 10;
    printf("%li\n", u->j[0]);
}
我想用
6.5
解释代码的合法性:

对象的存储值只能由左值访问 具有以下类型之一的表达式:

-与对象的有效类型兼容的类型

[……]

-一个 包含上述类型之一的聚合或联合类型 在其成员中(递归地包括子集合的成员 或包含在一起),或

将此应用于上述示例,我们得到:

  • u->i=10
    u->i
    对象提供有效类型
    int
  • 左值
    u
    有一个
    union
    类型,其中包含
    int
    类型的成员
  • 具有未指定值的对象
    u->j[0]
    可使用具有
    int
    类型成员的
    union u
    类型的左值
    u
    进行访问
  • 应用报价
    6.5
    我们发现这里没有UB

  • 问题:这样的推理正确吗?或者它包含一些错误?

    是的,您的推理是正确的。这不是未定义的行为,而是根据C11第6.2.6.1/7节:

    当值存储在联合类型的对象的成员中时 与之不对应的对象表示形式的字节数 成员,但与其他成员相对应,并采用未指定的值

    第3.19.3节阐明了这意味着什么:

    未指定的值:本国际标准未对其施加要求的相关类型的有效值 在任何情况下选择

    附件J:可移植性问题提醒了这一点

    J.1未指明的行为
    1以下未指定:
    -…
    -将值存储在结构或内存中时填充字节的值 活接头(6.2.6.1)
    -与并集对应的字节值 除最后存储到(6.2.6.1)中的成员以外的成员。
    -…

    J2中没有指定任何关于访问联合成员的内容,这与未定义的行为有关

    尽管如此,正如第6.2.6.1/6节提醒的那样,可移植性问题可能非常严重:

    结构或联合对象的值决不是陷阱 表示,即使结构或构件的值 联合对象可以是陷阱表示


    陷阱表示法是“不需要表示对象类型值的对象表示法”(定义),理解为“获取陷阱表示法可能执行陷阱,但不需要执行陷阱”(脚注)。因此,访问非活动值可能会导致程序中断,但如果不是这样,那就是无法保证

    无论使用何种别名规则,
    long
    int
    的大小是否相同取决于实现,因此
    u->j[0]
    有访问未初始化字节的风险,从而遇到陷阱值。也就是说,字节具有未指定的值。它并没有说由这些字节表示的对象具有未指定的值。@stantario:不正确。字节可能不是陷阱,但它们形成的值可能是陷阱。在这种情况下,最合适的规则是C 2018 6.5.2.3 3,它说,对于成员访问(使用
    ->
    ),“值是命名成员的值…”正如脚注中告诉我们的,这意味着联合中的字节,如果成员不是最后存储的成员,则重新解释为新类型。据了解,这告诉我们,通过联合使用别名是由C标准定义的(受类型表示的具体实现细节的影响)。我没有关于委员会对此进行审议的信息。1999年标准关于访问成员具有相同的规范性文本,但没有脚注。2007年的草案有脚注。我可能猜,在这两者之间,有一个关于解释的问题,因此添加了脚注,它被认为只是一个澄清,不值得更改规范性文本。@exnihilo感谢您指出!在尼格特的中间,我被工会和指针的相同名字弄糊涂了:“我要编辑这个令人困惑的名字,让我也做了一次双关。”