69

我可以在 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
4

10 回答 10

54

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

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

于 2010-03-06T02:08:19.510 回答
33

(这个答案适用于 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);
于 2009-12-28T23:18:02.877 回答
25

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

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

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

于 2011-11-11T20:39:40.413 回答
12

人们还可以随时执行以下操作:

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

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

于 2013-07-10T21:17:23.843 回答
8

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

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

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

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

于 2009-12-28T23:14:21.030 回答
3

我可以在 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 版权所有 (C) 2009 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。没有保修;甚至不考虑适销性或特定用途的适用性。

于 2010-01-29T19:05:11.233 回答
2

C 中也不支持匿名联合。

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

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

正在做

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));
于 2009-12-28T23:26:47.940 回答
0

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

于 2010-07-19T18:01:54.673 回答
0

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

所以我,专业地会和其他人一起去,只是给结构\联合成员一个标识符,或者在联合的情况下,仔细重新排列代码,以便联合最终成为一个已识别结构的已识别成员和成员被嵌入原始工会的未识别结构中,成为已识别结构的成员,并与已识别的工会成员一起仔细使用。但在那些情况下,如果后一种方法不是可行的替代品,我只会给烦人的结构一个标识符并继续前进。

于 2010-07-27T10:58:32.873 回答
-1

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

#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. */
于 2012-05-24T14:33:34.813 回答