簡體   English   中英

如何使用匿名結構/聯合編譯C代碼?

[英]How to compile C code with anonymous structs / unions?

我可以用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

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

-fms-extensions將啟用您(和我)想要的功能。

(這個答案適用於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);

在這種情況下,因為您的頂級結構有一個類型為union的項,您可以簡化:

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

現在訪問數據變為:

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

新的C11標准將支持匿名結構和工會,參見2011年4月草案的前言第6段。

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

奇怪的是,gcc和clang現在都支持C89和C99模式下的匿名結構和聯合。 在我的機器上沒有出現警告。

也可以始終執行以下操作:

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

如果您想要更加偏執,您可以手動指定數據打包策略以適合您的平台。

匿名聯合是C ++語言的一個特性。 C語言沒有匿名聯盟。

C和C ++都不存在匿名結構。

您在問題中提出的聲明可能會使用GCC C ++編譯器進行編譯,但它只是一個特定於編譯器的擴展,它與標准C和標准C ++無關。

最重要的是,無論你如何實現它,C語言和C ++語言都不能保證你的斷言能夠成立。

我可以在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。這是免費軟件; 查看復制條件的來源。 沒有保修; 甚至不適用於適銷性或特定用途的適用性。

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

C語言的GNU方言支持匿名結構/聯合,但默認情況下GCC使用某種標准C編譯。要使用GNU方言,請在命令行中輸入“-std = gnu99”。

不是ANSI / ISO C99標准的身份不明的結構成員解釋了這一點,但我發現一個有趣的事情發生在GNU C Compiler 2.xx版本的某些端口上,使用未識別的結構成員工作,它找到它們,並沒有說像“ x不是union \\ struct y的成員,什么是x?“,其他時候,它是ol'”x未定義“,”x不是struct的成員“,我發誓我看到了”指向未知的指針“ “有一段時間,由於這個原因。

所以我,專業地會與其他所有人一起去,只是以太給struct \\ union成員一個標識符,或者在UNIONs的情況下,仔細重新排列代碼,以便聯合結束已識別結構的已識別成員和成員嵌入原始聯合的未識別結構中,成為已識別結構的成員,並與已識別的工會成員一起使用。 但是在那些情況下,后一種方法不是一種可行的替代方法,我只是給annoynous結構一個標識符並繼續前進。

我可以建議一個有趣的解決方法,以避免結構中的太多字段。 建議人們警告簡單的命名定義,因為它可能會產生沖突。

#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. */

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM