Практическое использование битовых полей с нулевой длиной
Я не совсем уверен в C, но С++ допускает неназванные битовые поля длиной 0. Например:
struct X
{
int : 0;
};
- Вопрос 1. Какое практическое использование этого вы можете придумать?
- Вопрос второй: Какие практические применения в реальном мире (если есть) вы знаете?
Отредактированный пример после ответа на ледяную преступность
Изменить: Хорошо, благодаря текущим ответам я теперь знаю теоретическую цель. Но вопросы касаются практического использования, поэтому они все еще сохраняют:)
Ответы
Ответ 1
Вы используете бит-бит нулевой длины как хакерский способ заставить ваш компилятор выложить структуру для соответствия некоторому внешнему требованию, будь то другое представление компоновки или архитектуры макета (кросс-платформенные структуры данных, например, в бинарный формат файла) или стандартные требования к битовому уровню (сетевые пакеты или коды операций).
Реальный пример - когда NeXT портировал ядро xnu из архитектуры Motorola 68000 (m68k) в архитектуру i386. У NeXT была рабочая версия m68k их ядра. Когда они портировали его на i386, они обнаружили, что требования к выравниванию i386 отличаются от m68k таким образом, что машина m68k и машина i386 не согласны с компоновкой структуры BOOTP, специфичной для поставщика NeXT. Чтобы сделать структуру структуры i386 согласованной с m68k, они добавили неназванное битовое поле с нулевой длиной, чтобы объединение NV1
structure/nv_U
было согласовано с 16 битами.
Вот соответствующие части исходного кода Mac OS X 10.6.5 xnu:
/* from xnu/bsd/netinet/bootp.h */
/*
* Bootstrap Protocol (BOOTP). RFC 951.
*/
/*
* HISTORY
*
* 14 May 1992 ? at NeXT
* Added correct padding to struct nextvend. This is
* needed for the i386 due to alignment differences wrt
* the m68k. Also adjusted the size of the array fields
* because the NeXT vendor area was overflowing the bootp
* packet.
*/
/* . . . */
struct nextvend {
u_char nv_magic[4]; /* Magic number for vendor specificity */
u_char nv_version; /* NeXT protocol version */
/*
* Round the beginning
* of the union to a 16
* bit boundary due to
* struct/union alignment
* on the m68k.
*/
unsigned short :0;
union {
u_char NV0[58];
struct {
u_char NV1_opcode; /* opcode - Version 1 */
u_char NV1_xid; /* transcation id */
u_char NV1_text[NVMAXTEXT]; /* text */
u_char NV1_null; /* null terminator */
} NV1;
} nv_U;
};
Ответ 2
Стандарт (9.6/2) допускает только 0 бит бит-полей как специальный случай:
Как особый случай, неназванный бит-поле с шириной нуля указывает выравнивание следующего бит-поле в блоке выделения граница. Только при объявлении неназванное битовое поле может константное выражение будет равным значению до нуля.
Единственное использование описано в этой цитате, хотя я еще не встречался с ней в практическом коде.
Для записи я просто попробовал следующий код под VS 2010:
struct X {
int i : 3, j : 5;
};
struct Y {
int i : 3, : 0, j : 5; // nice syntax huh ?
};
int main()
{
std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl;
}
Выход на моей машине действительно: 4 - 8
.
Ответ 3
struct X { int : 0; };
- поведение undefined в C.
См. (основное внимание):
(C99, 6.7.2.1p2) "Наличие struct-declaration-list в struct-or-union-specifier объявляет новый тип в пределах единицы перевода. Список struct-declaration-list представляет собой последовательность объявления для членов структуры или объединения. Если в списке struct-declaration-list нет именованных членов, поведение undefined"
(C11 имеет ту же формулировку.)
Вы можете использовать безымянное битовое поле с шириной 0
, но не, если в структуре нет другого именованного элемента.
Например:
struct W { int a:1; int :0; }; // OK
struct X { int :0; }; // Undefined Behavior
Кстати, для второго объявления gcc
выдает диагностику (не требуемую стандартом C) с -pedantic
.
С другой стороны:
struct X { int :0; };
определяется в GNU C. Он используется, например, ядром Linux (include/linux/bug.h
), чтобы принудительно выполнить компиляцию с использованием следующего макроса, если условие истинно:
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
Ответ 4
Это от MSDN и не помечено как Microsoft Specific, поэтому я предполагаю, что это обычный стандарт С++:
Неименованное битовое поле шириной 0 принудительно выравнивает следующее поле бит на следующую границу типа, где type является типом элемента.