如何使用匿名结构/联合编译 C 代码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1972003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:43:45  来源:igfitidea点击:

How to compile C code with anonymous structs / unions?

c++cstructanonymousunions

提问by solinent

I can do this in c++/g++:

我可以在 c++/g++ 中做到这一点:

struct vec3 { 
    union {
        struct {
            float x, y, z;
        }; 
        float xyz[3];
    }; 
};

Then,

然后,

vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);

will work.

将工作。

How does one do this in c with gcc? I have

如何用 gcc 在 c 中做到这一点?我有

typedef struct {
    union {
        struct {
            float x, y, z;
        };
        float xyz[3];
    };
} Vector3;

But I get errors all around, specifically

但我到处都有错误,特别是

line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything

采纳答案by user287561

according to http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

根据http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

-fms-extensionswill enable the feature you (and I) want.

-fms-extensions将启用您(和我)想要的功能。

回答by R Samuel Klatchko

(This answer applies to C99, not C11).

(此答案适用于 C99,不适用于 C11)。

C99 does not have anonymous structures or unions. You have to name them:

C99 没有匿名结构或联合。您必须为它们命名:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

And then you have to use the name when accessing them:

然后您必须在访问它们时使用该名称:

assert(&v.data.xyz[0] == &v.data.individual.x);

In this case, because your top level structure has a single item of type union, you could simplify this:

在这种情况下,因为您的顶级结构只有一个类型为 union 的项目,您可以简化此操作:

typedef union {
    struct {
        float x, y, z;
    } individual;
    float xyz[3];
} Vector3;

and accessing the data now becomes:

并且访问数据现在变成:

assert(&v.xyz[0] == &v.individual.x);

回答by hdante

The new C11 standard will support anonymous structures and unions, see foreword paragraph 6 of the April 2011 draft.

新的 C11 标准将支持匿名结构和联合,请参阅 2011 年 4 月草案的前言第 6 段。

http://en.wikipedia.org/wiki/C1X

http://en.wikipedia.org/wiki/C1X

The strange part is that both gcc and clang now support anonymous structures and unions in C89 and C99 mode. In my machine no warnings appear.

奇怪的是 gcc 和 clang 现在都支持 C89 和 C99 模式下的匿名结构和联合。在我的机器中没有出现警告。

回答by Ionoclast Brigham

One can also always do the following:

也可以始终执行以下操作:

typedef struct
{
    float xyz[0];
    float x, y, z;
}Vec3;

The zero-length array doesn't allocate any storage, and just tells C to "point to whatever the next thing declared is." Then, you can access it just like any other array:

零长度数组不分配任何存储空间,只是告诉 C“指向下一个声明的内容”。然后,您可以像访问任何其他数组一样访问它:

int main(int argc, char** argv)
{
    Vec3 tVec;
    for(int i = 0; i < 3; ++i)
    {
        tVec.xyz[i] = (float)i;
    }

    printf("vec.x == %f\n", tVec.x);
    printf("vec.y == %f\n", tVec.y);
    printf("vec.z == %f\n", tVec.z);

    return 0;
}

Result:

结果:

vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000

If you want to be extra paranoid, you can manually specify the data packing strategy to suit your platform.

如果您想变得更加偏执,您可以手动指定适合您平台的数据打包策略。

回答by AnT

Anonymous unions is a feature of C++ language. C language has no anonymous unions.

匿名联合是 C++ 语言的一个特性。C 语言没有匿名联合。

Anonymous structs don't exist in neither C nor C++.

匿名结构在 C 和 C++ 中都不存在。

The declaration you presented in your question might compile with GCC C++ complier, but it would be just a compiler-specific extension, which has nothing to do with neither standard C nor standard C++.

您在问题中提出的声明可能会使用 GCC C++ 编译器进行编译,但这只是特定于编译器的扩展,与标准 C 和标准 C++ 都无关。

On top of that, regardless of how you implement it, neither C nor C++ language guarantees that your assertions will hold.

最重要的是,无论您如何实现它,C 和 C++ 语言都不能保证您的断言将成立。

回答by Afriza N. Arief

I can do this in GCC without warning

我可以在没有警告的情况下在 GCC 中执行此操作

typedef union {
    struct { // human-friendly access
        float x;
        float y;
        float z;
        float w;
    };
    float xyz[3];
    struct { // human-friendly access
        float r;
        float g;
        float b;
        float a;
    };
    float rgb[3];
} Vector4f;

int main()
{
    Vector4f position, normal, color;
    // human-friendly access
    position.x = 12.3f;
    position.y = 2.f;
    position.z = 3.f;
    position.w = 1.f;

    normal.x = .8f;
    normal.y = .9f;
    normal.z = .1f;
    normal.w = 1.f;

    color.r = 1.f;
    color.g = .233f;
    color.b = 2.11f;
    color.a = 1.1f;

    // computer friendly access
    //some_processor_specific_operation(position.vec,normal.vec);
    return 0;
}

C:\>gcc vec.c -Wall

C:\>gcc --version gcc (GCC) 4.4.0 Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C:\>gcc vec.c -Wall

C:\>gcc --version gcc (GCC) 4.4.0 版权所有 (C) 2009 Free Software Foundation, Inc。这是免费软件;请参阅复制条件的来源。没有保修;甚至不是为了特定目的的适销性或适合性。

回答by Afriza N. Arief

Anonymouse unions are nor supported in C.

C 中也不支持匿名联合。

Also note that if you declare it this way:

另请注意,如果您以这种方式声明:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

Doing

正在做

Vector3 v;
v.data.xyz[0] = 5;

float foo = v.data.individual.x;

Is an undefined behaviour. You can only access the last assigned union member. In your case, using an union is wrong and bad coding practice as it's dependent on many things that are not specified in the standard (padding...).

是未定义的行为。您只能访问最后分配的工会成员。在您的情况下,使用联合是错误且糟糕的编码实践,因为它依赖于标准中未指定的许多内容(填充...)。

In C you will prefer something like this:

在 C 中,你会更喜欢这样的东西:

typedef struct {
    float v[3];
} Vec3;

And if you don't want to use v[x] you might consider:

如果你不想使用 v[x] 你可以考虑:

#define X(V) ((V).v[0])

Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));

回答by David Grayson

The GNU dialect of C supports anonymous structs/unions, but by default GCC compiles using some kind of standard C. To use the GNU dialect, put "-std=gnu99" on the command line.

C 的 GNU 方言支持匿名结构/联合,但默认情况下 GCC 使用某种标准 C 进行编译。要使用 GNU 方言,请将“-std=gnu99”放在命令行上。

回答by DLCJ

Unidentified struct members not being ANSI/ISO C99 standard explains this, but I find a funny thing happens, on some ports of GNU C Compiler 2.x.x versions, using undentified struct members works, it finds them, doesn't say stuff like "x is not a member of union\struct y, what is x?", other times, it's the ol' "x is undefined", "x is not a member of struct", hell I swear I saw a "pointer to unknown" once a while back, due to this.

未识别的结构成员不是 ANSI/ISO C99 标准解释了这一点,但我发现发生了一件有趣的事情,在 GNU C 编译器 2.xx 版本的某些端口上,使用未识别的结构成员可以工作,它会找到它们,并没有说“ x 不是 union\struct y 的成员,x 是什么?”,其他时候,它是 ol'“x 未定义”,“x 不是 struct 的成员”,我发誓我看到了“指向未知的指针” ” 不久前,由于这个。

So I, professionally would go with everyone else on this and just ether give the struct\union member a identifier, or in the case of UNIONs, carefully rearrange the code so the union ends up an identified member of a identified structure and the members that were embedded in the unidentified structure of the original union, become members of the identified structure and are carefully used with the identified union member. But in those cases were the latter method would not be a workable substitute, I would just give the annoynous structure an identifier and move on.

所以我,专业上会和其他人一起做这件事,只是给 struct\union 成员一个标识符,或者在 UNIONs 的情况下,仔细地重新排列代码,这样联合最终会成为一个已识别结构的已识别成员,以及被嵌入到原始联合的未识别结构中,成为已识别结构的成员,并与已识别联合成员一起小心使用。但在那些情况下,后一种方法不是可行的替代品,我只会给这个讨厌的结构一个标识符并继续前进。

回答by Felipe Lavratti

I can suggest an interesting workaround in order to avoid too much fields within the structure. One is advised to warn about simply named defines, as it could create conflicts.

我可以提出一个有趣的解决方法,以避免结构中的字段过多。建议对简单命名的定义发出警告,因为它可能会产生冲突。

#define x    ___fl_fld[0]
#define y    ___fl_fld[1]
#define z    ___fl_fld[2]
#define w    ___fl_fld[3]
#define r    ___fl_fld[0]
#define g    ___fl_fld[1]
#define b    ___fl_fld[2]
#define a    ___fl_fld[3]
typedef union {
    float ___fl_fld[4];
    float xyz[3];
    float rgb[3];
} Vector3;

You could access the structure like this:

您可以像这样访问结构:

Vector3 v;
assert(&v.x == &v.r); //Should return true

To finish, this would be a multi type union compatible with C99:

最后,这将是一个与 C99 兼容的多类型联合:

#define u8llsb __u8[0]
#define u8lmsb __u8[1]
#define u8mlsb __u8[2]
#define u8mmsb __u8[3]
#define u16lsb __u16[0]
#define u16msb __u16[1]
#define u16    __u16[0]
#define u8lsb  __u8[0]
#define u8msb  __u8[1]

typedef union {
    uint32_t u32;
    int32_t  i32;
    uint16_t  __u16[2];
    uint8_t   __u8[4];
} multitype_t;

multitype_t Var;
var.u32;
var.i32;
var.u8llsb;
/* etc. */