Как указал Крис Латс, вы можете определить количество битов, которые использует переменная, добавив двоеточие и его размер: unsigned char myOneBitVariable:1;
и для вашего случая 'unsigned char MyFourBitVariable: 4'. Я хотел бы указать, как чрезвычайно сложно это и почему вы должны избегать этого .
Большинство современных компиляторов выравнивают пространство для ваших переменных в вашей структуре. Наиболее общий случай сегодня составляет 4 байта или даже 8 байтов, но это варьируется от платформы к платформе и от компилятора до компилятора. Некоторые компиляторы позволяют указывать выравнивание данных и их членов. В GCC ключевое слово __attribute__((aligned(x)))
, а в MSVC - __declspec(align(x))
. В большинстве случаев вам также нужно будет указать, сколько компилятор должен упаковать структуры. MSVC имеет директиву #pragma pack(x)
: http://msdn.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx. Вы также можете прочитать о выравнивании MSVC здесь: http://msdn.microsoft.com/en-us/library/83ythb65(VS.80).aspx. GCC имеет свою собственную реализацию под названием __attribute__ ((__packed__)
, которую вам, возможно, придется искать.
Пример, который не дает вам того, что вы хотите, используя компилятор Microsoft:
#ifndef _MSC_VER
#error This alignment solution / packing solution is only valid on MSC
#endif /* ifndef _MSC_VER */
#define M_ALIGN(x) __declspec(align(x))
struct S64Bits
{
unsigned char MyOneBitVariable:1;
int My32BitInt;
};
// MSVC specific implementation of data-packing in a type.
#pragma pack(1)
struct S32Bits
{
D_ALIGN(1) int My16BitVariable:16;
D_ALIGN(1) unsigned char Padding8Bits;
D_ALIGN(1) unsigned char MyOneBitVariable1:1;
D_ALIGN(1) unsigned char MyOneBitVariable2:1;
D_ALIGN(1) unsigned char MyOneBitVariable3:1;
D_ALIGN(1) unsigned char MyOneBitVariable4:1;
D_ALIGN(1) unsigned char MyFourBitVariable:4;
};
#pragma pack(pop)
'sizeof (S64Bits)' должен быть 8, что и есть. sizeof (S32Bits) должен быть 4, это не . На MSVC последний составляет 6 байтов. Поведение также зависит от компилятора и часто имеет уникальные для компилятора директивы. Такое поведение почти никогда не дает вам то, что вы хотите. Я часто использую макрос, чтобы убедиться, что структуры, которые мне требуются, имеют определенный размер:
#define TEST_TYPE_SIZE(Type, Size) assert(sizeof(Type) == Size);
Что я буду использовать ниже всех своих типов данных, где я пытаюсь указать их точный размер. Однако полагаться на то, что структура имеет любой размер, отличный от sizeof (mystructure), - это кодирование, которое, вероятно, приведет к трудностям при отладке ошибок. Директивы компилятора выравнивания лучше всего подходят для выравнивания данных по размеру строки кэша и аналогичным проблемам эффективности.
Карл Билефельдт (Karl Bielefeldt) предлагает хорошее естественное решение для хранения 4-битных значений в uint8 с использованием операций сдвига битов, используйте их вместо этого.