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

发布于 2024-08-15 18:43:29 字数 672 浏览 7 评论 0原文

我可以在 c++/g++ 中执行此操作:

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

然后,

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

就可以了。

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

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

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

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

I can do this in 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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

请帮我爱他 2024-08-22 18:43:29

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

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

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

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

玉环 2024-08-22 18:43:29

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

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

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

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

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

在这种情况下,因为你的顶级结构有一个联合类型的单个项目,你可以简化这一点:

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

并且访问数据现在变成:

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

(This answer applies to C99, not C11).

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

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:

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);
风筝有风,海豚有海 2024-08-22 18:43:29

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

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

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

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

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.

芸娘子的小脾气 2024-08-22 18:43:29

人们还可以始终执行以下操作:

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

零长度数组不分配任何存储,只是告诉 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;
}

结果:

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

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

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:

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.

豆芽 2024-08-22 18:43:29

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

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

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

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

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

Anonymous structs don't exist in neither C nor 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++.

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

残疾 2024-08-22 18:43:29

我可以在 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 --版本
海湾合作委员会(海湾合作委员会)4.4.0
版权所有 (C) 2009 自由软件基金会, Inc.
这是免费软件;请参阅复制条件的来源。没有
保修单;甚至不是为了适销性或特定用途的适用性。

I can do this in GCC without warning

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.

来世叙缘 2024-08-22 18:43:29

C 中也不支持匿名联合。

另请注意,如果您这样声明:

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;

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

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

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

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

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

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

Anonymouse unions are nor supported in 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:

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

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

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

Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));
泪之魂 2024-08-22 18:43:29

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

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.

痕至 2024-08-22 18:43:29

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

因此,在专业上,我会与其他人一起解决这个问题,只是为 struct\union 成员提供一个标识符,或者在 UNION 的情况下,仔细地重新排列代码,以便 union 最终成为已识别结构的已识别成员,以及嵌入到原始联合体的未识别结构中,成为已识别结构的成员,并与已识别的联合体成员谨慎使用。
但在这些情况下,如果后一种方法不是可行的替代品,我只会给讨厌的结构一个标识符并继续。

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.

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.

最美的太阳 2024-08-22 18:43:29

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

#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;

您可以像这样访问结构:

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

最后,这将是与 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. */

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:

#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. */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文