我有一些与以下代码非常相似的代码
struct T {
union {
unsigned int x;
struct {
unsigned short xhigh;
unsigned short xlow;
};
} x;
/* ...repeated a handful of times for different variables in T... */
};
这正是您所期望的:它允许我声明类型为
struct T
的变量并访问 t.x.x
或 t.x.xhigh
或 t.x.xlow
。到目前为止一切顺利。
但是,如果我能够在常见情况下只做
t.x
,即想要以unsigned int
数量的形式访问联合的值,但保留访问高和低的能力,我真的很喜欢它独立地对部分进行排序,而无需诉诸位掩码和移位,也不会调用未定义的行为。
这在C语言中可能吗?
如果可以的话,声明的C语法是什么?
当我尝试简单地访问
t.x
而不是 t.x.x
的幼稚方法时,我收到如下警告消息(这个特定的消息来自 printf()
调用):
cc -ansi -o test -Wall test.c
test.c: In function ‘my_function’:
test.c:13:2: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 2 has type ‘const union <anonymous>’ [-Wformat]
使用
-std=c11
代替 -ansi
会产生相同的警告。
如果您可以使用匿名结构,则匿名联合是一回事(它们都是 C11 功能或编译器扩展)。
正如您使用没有名称的
struct
将其成员注入到联合的命名空间中一样,您也可以使用没有名称的 union
将其成员注入到封闭的命名空间中。像这样:
struct T {
union {
unsigned int x;
struct {
unsigned short xhigh;
unsigned short xlow;
};
}; /* <-- no name here */
/* ...repeated a handful of times for different variables in T... */
};
您只需确保注入的名称不会与其他注入的名称或存在的常规名称冲突,否则它将无法编译。
但有一个问题:您似乎依赖于“事实”,即
unsigned short
的大小是 unsigned int
的一半,并且这些类型是大端字节序。但如果这就是您的系统上发生的情况,那就没问题了。如果没有,我建议你重新考虑结构。
另一个选项,仍然允许使用联合名称(例如在其上使用 sizeof() ),它使用一种类似的 hack:
#define _union_ddef(name, list...) \
union { \
union { list }; \
union { list } name; \
}
然后,根据您的情况,您可以这样做:
struct T {
_union_ddef(u,
unsigned int x;
struct {
unsigned short xhigh;
unsigned short xlow;
};
);
/* ...repeated a handful of times for different variables in T... */
};
显然,工会和工会成员不能使用相同的名字,避免命名上出现任何其他“冲突”。我确实用
x
替换了上面之前的 u
联合名称。
预处理器会将 T
定义替换为:
struct T {
union {
union { /* here with no name */
unsigned int x;
struct {
unsigned short xhigh;
unsigned short xlow;
};
};
union { /* and here with a name */
unsigned int x;
struct {
unsigned short xhigh;
unsigned short xlow; };
} u;
};
};
现在您可以使用带或不带名称的联合:
#include <stdio.h>
int main()
{
struct T s;
/* Then, you can access x with or without the union name */
s.x = 42; printf("x=%u\n", s.u.x);
s.u.x = 24; printf("x=%u\n", s.x);
s.xhigh = 422; printf("x=%u\n", s.u.xhigh);
s.u.xhigh = 224; printf("x=%u\n", s.xhigh);
/* and you can use the union name for something else */
printf("union size=%lu\n", sizeof (s.u));
}
结果:
$ ./a
x=42
x=24
x=422
x=224
union size=4
使用结构而不是联合也可以完成同样的操作。