如果我宣布联盟为:
union TestUnion
{
struct
{
unsigned int Num;
unsigned char Name[5];
}TestStruct;
unsigned char Total[7];
};
现在,我怎么知道是使用了Total [7]还是使用了TestStruct?
我正在使用C!
我正在重新审视工会和结构,我想到了这个问题。
不能使用“sizeof
”,因为两者具有相同的大小,即7个字节。 (还有另一个问题)
当我只填充字符'a'和Tried sizeof(TestUnionInstance)
的“Total”时,它返回12(Char的大小为1字节,对吗?)。所以我从中分离出结构,发现结构的大小是12个字节而不是5 + 2 = 7个字节....奇怪!!
任何人都可以解释??
P.S。我正在使用Visual Studio 2008。
答案 0 :(得分:21)
你做不到。这是工会的一部分。
如果您需要告诉,您可以使用称为标记联合的东西。有些语言对这些语言有内置支持,但在C语言中,你必须自己做。我们的想法是包含一个标记以及union,您可以使用它来分辨它是哪个版本。像:
enum TestUnionTag {NUM_NAME, TOTAL};
struct {
enum TestUnionTag tag;
union {
struct {
unsigned int Num;
unsigned char Name[5];
} TestStruct;
unsigned char Total[7];
} value;
} TestUnion;
然后在您的代码中,确保始终设置标记以说明如何使用联合。
关于sizeof:struct是12个字节,因为int有4个字节(大多数现代编译器有4个字节的int,与long int相同),然后是3个字节的填充和5个字节的字符(我不知道填充是在字符之前还是之后)。填充是存在的,因此结构是长整数个字,因此内存中的所有内容在字边界上保持对齐。因为结构长度为12个字节,所以联合必须长12个字节来保存它;联盟不会根据其中的内容改变大小。
答案 1 :(得分:6)
使用的成员是你上次写的那个;其他人是禁区。你知道你上次写信的成员,不是吗?毕竟,是你编写程序的人: - )
至于你的第二个问题:允许编译器在结构中插入“填充字节”,以避免未对齐的访问并使其更具性能。
example of a possible distribution of bytes inside your structure Num |Name |pad - - - -|- - - - -|x x x 0 1 2 3|4 5 6 7 8|9 a b
答案 2 :(得分:4)
简短的回答:除了在你的结构中的某个地方添加枚举之外,没有办法。
enum TestUnionPart
{
TUP_STRUCT,
TUP_TOTAL
};
struct TestUnionStruct
{
enum TestUnionPart Part;
union
{
struct
{
unsigned int Num;
unsigned char Name[5];
} TestStruct;
unsigned char Total[7];
} TestUnion;
};
现在您需要控制联合的创建以确保正确设置枚举,例如使用类似于以下的函数:
void init_with_struct(struct TestUnionStruct* tus, struct TestStruct const * ts)
{
tus->Part = TUP_STRUCT;
memcpy(&tus->TestUnion.TestStruct, ts, sizeof(*ts));
}
发送正确的值现在只需一个开关:
void print(struct TestUnionStruct const * tus)
{
switch (tus->Part)
{
case TUP_STRUCT:
printf("Num = %u, Name = %s\n",
tus->TestUnion.TestStruct.Num,
tus->TestUnion.TestStruct.Name);
break;
case TUP_TOTAL:
printf("Total = %s\n", tus->TestUnion.Total);
break;
default:
/* Compiler can't make sure you'll never reach this case */
assert(0);
}
}
作为旁注,我想提一下,这些结构最好用ML系列的语言处理。
type test_struct = { num: int; name: string }
type test_union = Struct of test_struct | Total of string
答案 3 :(得分:2)
首先,现在大多数架构上的sizeof(int)
将是4.如果你想要2,你应该在C99的short
标题中查看int16_t
或stdint.h
如果你想具体。
其次,C使用填充字节来确保每个struct
与字边界对齐(4)。所以你的结构看起来像这样:
+---+---+---+---+---+---+---+---+---+---+---+---+
| Num | N a m e | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+
最后有3个字节。否则,数组中的下一个struct
会在一个位置不对齐的地方放置Num
字段,这会降低访问效率。
第三,sizeof
联盟将是sizeof
最大的成员。即使未使用所有空间,sizeof
也将返回最大的结果。
正如其他答案提到的那样,你需要一些其他方式(比如enum
)来确定你的联合中使用哪个字段。
答案 4 :(得分:1)
没有办法说出来。你应该有一些额外的标志(或你工会外部的其他方法),说明哪些联合部分真正使用过。
答案 5 :(得分:0)
另一个示例,该示例将联合与枚举包括在一起以确定要存储的内容。我发现它更清楚明确了。
来自: https://www.cs.uic.edu/~jbell/CourseNotes/C_Programming/Structures.html
作者: 约翰·T·贝尔博士
为了知道实际存储哪个联合字段,联合通常嵌套在结构内部,并使用枚举类型指示实际存储在其中的内容。例如:
typedef struct Flight {
enum { PASSENGER, CARGO } type;
union {
int npassengers;
double tonnages; // Units are not necessarily tons.
} cargo;
} Flight;
Flight flights[ 1000 ];
flights[ 42 ].type = PASSENGER;
flights[ 42 ].cargo.npassengers = 150;
flights[ 20 ].type = CARGO;
flights[ 20 ].cargo.tonnages = 356.78;