我手头有一个例子,其中类型的对齐是通过 union max_align 来保证的。我正在寻找一个更简单的例子,其中实际使用 union,以便向我的朋友解释。
我手头有一个例子,其中类型的对齐是通过 union max_align 来保证的。我正在寻找一个更简单的例子,其中实际使用 union,以便向我的朋友解释。
当我解析文本时,通常使用联合体。我使用类似于以下的代码:
typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;
typedef union DataValue
{
int v_int;
float v_float;
char* v_string;
}DataValue;
typedef struct DataNode
{
DataType type;
DataValue value;
}DataNode;
void myfunct()
{
long long temp;
DataNode inputData;
inputData.type= read_some_input(&temp);
switch(inputData.type)
{
case INTEGER: inputData.value.v_int = (int)temp; break;
case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
case STRING: inputData.value.v_string = (char*)temp; break;
}
}
void printDataNode(DataNode* ptr)
{
printf("I am a ");
switch(ptr->type){
case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
case STRING: printf("String with value %s", ptr->value.v_string); break;
}
}
如果你想看如何大量使用union,可以查看任何使用flex/bison的代码。例如,可以看看splint,它包含了大量的union。
在需要查看数据的不同方面时,我通常使用联合(unions)。 例如,当你想要查看32位颜色值时,你可以同时查看32位值以及红、绿、蓝和透明度组件。
struct rgba
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
union
{
unsigned int val;
struct rgba components;
}colorval32;
#define GETR(val) ((val&0xFF000000) >> 24)
但我认为联合方法更加优雅
struct rgba
可能具有填充,即使没有填充,sizeof(unsigned int)
也可能不等于 sizeof(struct rgba)
(没有填充为4)。也就是说,你可能不想这样做。 - Alok Singhalstruct
中的r
,g
,b
和a
字段会按顺序出现(有或没有填充),而unsigned int
字节顺序将取决于大小端。换句话说,这段代码不可移植,在另一个处理器上编译时可能会以奇怪的方式失败。 - David Thornley如果要通过将特定端口映射到内存来按字节和按位访问寄存器或I/O端口,请参见以下示例:
typedef Union
{
unsigned int a;
struct {
unsigned bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1,
bit8 : 1,
bit9 : 1,
bit10 : 1,
bit11 : 1,
bit12 : 1,
bit13 : 1,
bit14 : 1,
bit15 : 1
} bits;
} IOREG;
# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation
unions
通常用于实现标记变量,这是(或在.NET之前?)在COM对象之间传递数据的一种标准方式。union
类型可以提供一个单一的自然接口,用于在两个对象之间传递任意数据。某些COM对象可以向您传递一个变量(例如类型为VARIANT
或_variant_t
的变量),其中可能包含double
、float
、int
或其他类型的数据。struct cat_info
{
int legs;
int tailLen;
};
struct fish_info
{
bool hasSpikes;
};
union
{
fish_info fish;
cat_info cat;
} animal_data;
struct animal
{
char* name;
int animal_type;
animal_data data;
};
如果你有不同类型的消息,使用联合体很有用,这样你就不需要在任何中间级别了解确切类型。只有发送者和接收者需要解析实际消息。任何其他级别只需要知道尺寸和可能的发送者和/或接收者信息。
你是指像这样的吗?
union {
long long a;
unsigned char b[sizeof(long long)];
} long_long_to_single_bytes;
新增内容:
最近我在我们的AIX机器上使用了这个方法,将64位机器标识符转换为字节数组。
std::string getHardwareUUID(void) {
#ifdef AIX
struct xutsname m; // aix specific struct to hold the 64bit machine id
unamex(&b); // aix specific call to get the 64bit machine id
long_long_to_single_bytes.a = m.longnid;
return convertToHexString(long_long_to_single_bytes.b, sizeof(long long));
#else // Windows or Linux or Solaris or ...
... get a 6byte ethernet MAC address somehow and put it into mac_buf
return convertToHexString(mac_buf, 6);
#endif
我有时会这样使用联合体
//Define type of structure
typedef enum { ANALOG, BOOLEAN, UNKNOWN } typeValue_t;
//Define the union
typedef struct {
typeValue_t typeValue;
/*On this structure you will access the correct type of
data according to its type*/
union {
float ParamAnalog;
char ParamBool;
};
} Value_t;
然后你可以声明不同类型的数组,更高效地存储数据,并进行一些“多态”操作,例如:
void printValue ( Value_t value ) {
switch (value.typeValue) {
case BOOL:
printf("Bolean: %c\n", value.ParamBool?'T':'F');
break;
case ANALOG:
printf("Analog: %f\n", value.ParamAnalog);
break;
case UNKNOWN:
printf("Error, value UNKNOWN\n");
break;
}
}
这里是另一个使用联合体可能有用的例子。
(不是我的想法,我在一份讨论c++优化的文档中发现了这个想法)
引用开始
...联合体也可以用于节省空间,例如:
首先是非联合方法:
void F3(bool useInt) {
if (y) {
int a[1000];
F1(a); // call a function which expects an array of int as parameter
}
else {
float b[1000];
F2(b); // call a function which expects an array of float as parameter
}
}
在这里,可以使用相同的内存区域来存储a和b,因为它们的生命周期不重叠。通过将a和b合并到一个联合体中,您可以节省大量cpu-cache空间:
void F3(bool useInt) {
union {
int a[1000];
float b[1000];
};
if (y) {
F1(a); // call a function which expects an array of int as parameter
}
else {
F2(b); // call a function which expects an array of float as parameter
}
}
使用联合是一个不安全的编程实践,因为如果a和b的使用重叠,编译器会没有任何警告。你只应该在需要大量缓存空间的大型对象上使用这种方法。
结束引用