Как узнать, какая переменная используется в Union?
Если я объявляю Союз как:
union TestUnion
{
struct
{
unsigned int Num;
unsigned char Name[5];
}TestStruct;
unsigned char Total[7];
};
Теперь, откуда я могу узнать, используется ли Total [7] или используется TestStruct?
Я использую C!
Я пересматривал союзы и структуры, и этот вопрос пришел мне на ум.
"sizeof
" не может использоваться, поскольку оба имеют одинаковый размер, т.е. 7 байтов. (И вот еще один вопрос)
Когда я заполнил только "Total" символом "a" и пробовал sizeof(TestUnionInstance)
, он вернул 12 (размер Char равен 1 байт, правильно?). Поэтому я выделил структуру из нее и обнаружил, что размер структуры составляет 12 байт, а не 5 + 2 = 7 байт.... Странно!!
Кто-нибудь может объяснить?
P.S. Я использую Visual Studio 2008.
Ответы
Ответ 1
Вы не можете. Эта часть точки союзов.
Если вам нужно сказать, вы можете использовать что-то, называемое объединенным тегом. Некоторые языки имеют встроенную поддержку для них, но в C вы должны сделать это самостоятельно. Идея состоит в том, чтобы добавить тег вместе с объединением, который вы можете использовать, чтобы определить, какая версия. Как:
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), затем три байта заполнения и пять байтов для символов (я не знаю, доходит ли дополнение до или после символов). Отступы существуют, так что структура представляет собой целое число слов в длину, так что все в памяти сохраняется на границах слов. Поскольку структура имеет длину 12 байтов, объединение должно быть 12 байтов для ее хранения; объединение не меняет размер в соответствии с тем, что в нем.
Ответ 2
Член, которого вы используете, - это тот, который вы в последний раз писали; другие не имеют пределов. Вы знаете, к кому вы, в конце концов, писали, не так ли? В конце концов, именно вы написали программу: -)
Как для вас вторичный вопрос: компилятору разрешено вставлять "заполняющие байты" в структуру, чтобы избежать несвязанных обращений и сделать его более результативным.
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
Ответ 3
Короткий ответ: нет способа, кроме как добавив перечисление где-нибудь в вашей структуре вне союза.
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
Ответ 4
Во-первых, sizeof(int)
для большинства архитектур в настоящее время будет 4. Если вы хотите 2, вы должны посмотреть short
или int16_t
в заголовке stdint.h
на C99, если хотите быть конкретным.
Во-вторых, C использует байты заполнения, чтобы каждый struct
был привязан к границе слова (4). Итак, ваша структура выглядит следующим образом:
+---+---+---+---+---+---+---+---+---+---+---+---+
| Num | N a m e | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+
В конце 3 байта. В противном случае следующий struct
в массиве будет иметь поле Num
в неудобно выровненном месте, что сделает его менее эффективным для доступа.
В-третьих, объединение sizeof
будет самым большим членом sizeof
. Даже если все это пространство не используется, sizeof
вернет самый большой результат.
Вам нужно, как говорили другие ответы, каким-то другим способом (например, enum
) определить, какое поле вашего объединения используется.
Ответ 5
Невозможно сказать. У вас должны быть дополнительные флаги (или другие средства, внешние по отношению к вашему объединению), говорящие, какая из частей соединения действительно используется.