键入双关的C和C ++结构通过工会 [英] Type punning a struct in C and C++ via a union

查看:178
本文介绍了键入双关的C和C ++结构通过工会的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在gcc和g ++与迂腐编译这和我没有得到在任何一个警告:

I've compiled this in gcc and g++ with pedantic and I don't get a warning in either one:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct a {
    struct a *next;
    int i;
};

struct b {
    struct b *next;
    int i;
};

struct c {
    int x, x2, x3;
    union {
        struct a a;
        struct b b;
    } u;
};

void foo(struct b *bar) {
    bar->next->i = 9;
    return;
}

int main(int argc, char *argv[]) {
    struct c c;
    memset(&c, 0, sizeof c);
    c.u.a.next = (struct a *)calloc(1, sizeof(struct a));
    foo(&c.u.b);
    printf("%d\n", c.u.a.next->i);
    return 0;
}

这是合法的C和C ++做?我读过有关类型,双关,但我不明白。为富(安培; c.u.b)任何从不同美孚((结构的b *)及c.u.a)?难道他们不会完全一样?这(从C89在3.3.2.3)工会例外结构说:

Is this legal to do in C and C++? I've read about the type-punning but I don't understand. Is foo(&c.u.b) any different from foo((struct b *)&c.u.a)? Wouldn't they be exactly the same? This exception for structs in a union (from C89 in 3.3.2.3) says:

如果一个联合包含具有共同的初始几个结构
  序列,如果联合对象当前包含的其中之一
  的结构,它允许检查的任何常见的初始部分
  他们的。 两个结构共享,如果公共初始序列
  相应部件具有兼容的类型的一个或一个序列
  多个初始成员。

If a union contains several structures that share a common initial sequence, and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them. Two structures share a common initial sequence if corresponding members have compatible types for a sequence of one or more initial members.

在工会的结构的第一个成员一个结构旁边的* ,和的第一个成员结构b 结构b *的下一个。正如你可以看到指针结构旁边的* 写,然后在foo的指针结构b *的下一个被读出。他们是兼容的类型?他们都指向一个结构和指向任何结构应该是相同的大小,所以他们应该是兼容的布局应该是一样的吧?它是确定读 I 从一个结构和写入其他?我是不是犯任何类型的别名或类型双关侵犯?

In the union the first member of struct a is struct a *next, and the first member of struct b is struct b *next. As you can see a pointer to struct a *next is written, and then in foo a pointer to struct b *next is read. Are they compatible types? They're both pointers to a struct and pointers to any struct should be the same size, so they should be compatible and the layout should be the same right? Is it ok to read i from one struct and write to the other? Am I committing any type of aliasing or type-punning violation?

推荐答案

在C:

结构A 结构b 不兼容的类型。即使在

struct a and struct b are not compatible types. Even in

typedef struct s1 { int x; } t1, *tp1;
typedef struct s2 { int x; } t2, *tp2;

S1 S2 不兼容的类型。 (参见例如在6.7.8 / P5)。一种简单的方法,以确定非兼容结构是,如果两个结构类型是兼容的,则一些一种类型的可分配给其它类型的东西。如果你所期望的编译器,当你试图做到这一点,那么他们是不兼容的类型抱怨。

s1 and s2 are not compatible types. (See example in 6.7.8/p5.) An easy way to identify non-compatible structs is that if two struct types are compatible, then something of one type can be assigned to something of the other type. If you would expect the compiler to complain when you try to do that, then they are not compatible types.

因此​​,结构A * 结构的b * 也是不兼容的类型,所以结构体在结构b 不共享通用初始序列。

Therefore, struct a * and struct b * are also not compatible types, and so struct a and struct b do not share a common initial subsequence. Your union-punning is instead governed by the same rule for union punning in other cases (6.5.2.3 footnote 95):

如果用于读取联合对象的内容的部件是不
  相同构件最后用于存储在对象的值,则
  值的对象重新presentation的适当部分是
  reinter PTED作为新类型的对象重新presentation $ P $所描述
  在6.2.6(一个过程有时被称为'型双关语'')。这可能是
  陷阱重新presentation。

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

在C ++中,结构A 结构b 还没有共享一个通用初始序列。 [class.mem] / P18(报价N4140):


In C++, struct a and struct b also do not share a common initial subsequence. [class.mem]/p18 (quoting N4140):

两个标准布局结构共享,如果公共初始序列
  相应的成员具有布局兼容的类型,要么没有
  构件是一个位域或两者都位字段与一个相同的宽度
  一个或多个初始成员序列

Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.

[basic.types] / P9:

[basic.types]/p9:

如果两种类型 T1 T2 都是同一类型,那么 T1 T2
  的布局兼容的类型。 [注意的:布局兼容枚举在7.2描述。布局兼容的标准布局和结构
  标准布局工会9.2描述。 - 注完的]

If two types T1 and T2 are the same type, then T1 and T2 are layout-compatible types. [ Note: Layout-compatible enumerations are described in 7.2. Layout-compatible standard-layout structs and standard-layout unions are described in 9.2. —end note ]

结构A * 结构的b * 既不结构也不是工会,也不枚举;因此它们是唯一的布局兼容如果它们是相同的类型,它们是不

struct a * and struct b * are neither structs nor unions nor enumerations; therefore they are only layout-compatible if they are the same type, which they are not.

这是事实,([basic.compound] / P3)

It is true that ([basic.compound]/p3)

指针到CV-合格,CV-不合格的版本(3.9.3)的
  布局兼容的类型应重新presentation相同的值,
  对齐要求(3.11)。

Pointers to cv-qualified and cv-unqualified versions (3.9.3) of layout-compatible types shall have the same value representation and alignment requirements (3.11).

但是,这并不意味着这些指针类型是布局兼容的类型,该术语标准中定义。

But that does not mean those pointer types are layout-compatible types, as that term is defined in the standard.

这篇关于键入双关的C和C ++结构通过工会的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆