如何使用结构中的联合访问 C 结构
How to access C structs with a union within a struct
我正在使用别人的 C 代码,他们在其中定义了以下内容:
typedef struct {
union{
struct{
int A; // some data
} structA;
struct{
char B; // some alternative data
} structB;
} myUnion;
} myStruct;
你好。在代码的前面,这些巨型结构被声明、分配和填充数据。我正在处理后面的代码部分,我将在其中传递一个指向这些结构之一的指针,并且必须 (A) 确定是否使用了 structA 或 structB 类型,然后 (B) 读取实际数据。类似于:
void myFunction(myStruct *s){
if(s->myUnion.structA != NULL) // compilation error here
printf("This myStruct uses a structA, internal data is: %d\n", s->myUnion.structA.A);
else
printf("This myStruct uses a structB, internal data is: %c\n", s->myUnion.structB.B);
}
显然上面没有编译:
me@Linux:/home/me# gcc -Wall structsUnions.c
structsUnions.c: In function 'myFunction':
structsUnions.c:22:19: error: invalid operands to binary != (have 'struct <anonymous>' and 'void *')
if(s->myUnion.structA != NULL)
^
me@Linux:/home/me#
但我无能为力地想弄清楚这里的语法。
必须有一种方法可以进入 myStruct 并确定 structA 或 structB 是否在 myUnion 中。
有什么想法吗?
myUnion 是一个 union
,不是一个有两个成员的结构。
这意味着 structA
和 structB
共享相同的内存(在大多数 C 实现中)。
它还意味着 char B
和 int A
共享相同的内存(同样,在大多数 C 实现中),因此实际上没有办法判断使用了哪个构造。
ANSI 定义一个联合至少与其最大的成员一样大,并且它必须持有其中一个成员。
它的目标是高效实现所有成员重用相同的内存。
当然,在某些实现中,对齐问题可能会导致某些成员不与其他成员重叠,但我想不出一个我所知道的不与最大成员对齐的成员。
由于您共享的代码不包含指示 A
或 B
成员是否实际使用的标记字段,因此没有具体的方法可以确定在任何具体实例。
但是,根据您获得的数据,您可能能够在您的代码中做出有根据的猜测。例如,假设我在使用 IEEE 754 浮点类型的系统上有以下联合:
typedef union _F_or_I
{
float f;
int32_t i;
uint32_t bits;
} F_or_I;
如果前9位(符号和指数)全为0,则可能不是浮点数:
F_or_I foo = /* some value */;
if(!(foo.bits & 0xFF800000))
{
// access member 'i'
}
else
{
// access member 'f'
}
当然,这种方式并不总是准确的,具体取决于您在联合中使用的确切类型(对于我的示例中使用的类型,我什至不会依赖它!),以及执行此操作的正确方法是在父 struct
中包含一个 'tag' 成员,指示要访问哪个联合成员。
特别是,if(s->myUnion.structA != NULL)
中的编译错误是因为您无法检查结构是否为空,而只能检查结构的成员是否为零:
if(s->myUnion.structA.A != 0)
我正在使用别人的 C 代码,他们在其中定义了以下内容:
typedef struct {
union{
struct{
int A; // some data
} structA;
struct{
char B; // some alternative data
} structB;
} myUnion;
} myStruct;
你好。在代码的前面,这些巨型结构被声明、分配和填充数据。我正在处理后面的代码部分,我将在其中传递一个指向这些结构之一的指针,并且必须 (A) 确定是否使用了 structA 或 structB 类型,然后 (B) 读取实际数据。类似于:
void myFunction(myStruct *s){
if(s->myUnion.structA != NULL) // compilation error here
printf("This myStruct uses a structA, internal data is: %d\n", s->myUnion.structA.A);
else
printf("This myStruct uses a structB, internal data is: %c\n", s->myUnion.structB.B);
}
显然上面没有编译:
me@Linux:/home/me# gcc -Wall structsUnions.c
structsUnions.c: In function 'myFunction':
structsUnions.c:22:19: error: invalid operands to binary != (have 'struct <anonymous>' and 'void *')
if(s->myUnion.structA != NULL)
^
me@Linux:/home/me#
但我无能为力地想弄清楚这里的语法。
必须有一种方法可以进入 myStruct 并确定 structA 或 structB 是否在 myUnion 中。
有什么想法吗?
myUnion 是一个 union
,不是一个有两个成员的结构。
这意味着 structA
和 structB
共享相同的内存(在大多数 C 实现中)。
它还意味着 char B
和 int A
共享相同的内存(同样,在大多数 C 实现中),因此实际上没有办法判断使用了哪个构造。
ANSI 定义一个联合至少与其最大的成员一样大,并且它必须持有其中一个成员。
它的目标是高效实现所有成员重用相同的内存。
当然,在某些实现中,对齐问题可能会导致某些成员不与其他成员重叠,但我想不出一个我所知道的不与最大成员对齐的成员。
由于您共享的代码不包含指示 A
或 B
成员是否实际使用的标记字段,因此没有具体的方法可以确定在任何具体实例。
但是,根据您获得的数据,您可能能够在您的代码中做出有根据的猜测。例如,假设我在使用 IEEE 754 浮点类型的系统上有以下联合:
typedef union _F_or_I
{
float f;
int32_t i;
uint32_t bits;
} F_or_I;
如果前9位(符号和指数)全为0,则可能不是浮点数:
F_or_I foo = /* some value */;
if(!(foo.bits & 0xFF800000))
{
// access member 'i'
}
else
{
// access member 'f'
}
当然,这种方式并不总是准确的,具体取决于您在联合中使用的确切类型(对于我的示例中使用的类型,我什至不会依赖它!),以及执行此操作的正确方法是在父 struct
中包含一个 'tag' 成员,指示要访问哪个联合成员。
特别是,if(s->myUnion.structA != NULL)
中的编译错误是因为您无法检查结构是否为空,而只能检查结构的成员是否为零:
if(s->myUnion.structA.A != 0)