Nice programing

익명 구조체 / 공용체로 C 코드를 컴파일하는 방법은 무엇입니까?

nicepro 2020. 11. 20. 09:35
반응형

익명 구조체 / 공용체로 C 코드를 컴파일하는 방법은 무엇입니까?


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 귀하 (그리고 나)가 원하는 기능을 활성화합니다.


(이 답변은 C11이 아닌 C99에 적용됩니다).

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;

길이가 0 인 배열은 스토리지를 할당하지 않고 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-벽

C : \> gcc --version gcc (GCC) 4.4.0 Copyright (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));

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.


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.


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

참고URL : https://stackoverflow.com/questions/1972003/how-to-compile-c-code-with-anonymous-structs-unions

반응형