Практическое использование битовых полей нулевой длины
Я не совсем уверен в C, но C++ допускает неназванные битовые поля длиной 0. Например:
struct X
{
int : 0;
};
- Вопрос первый: Какие практические применения этого может вы думать?
- вопрос второй: Какие реальные практические применения (если таковые имеются) вы знаете?
редактировать пример после ответа ice-crime
Edit: OK, благодаря текущим ответам я теперь знаю теоретическую цель. Но вопросы о практическом использовании, так что они все еще держат:)
5 ответов
вы используете битовое поле нулевой длины как хакерский способ заставить компилятор выложить структуру, соответствующую некоторым внешним требованиям, будь то представление другого компилятора или архитектуры о макете (кросс-платформенные структуры данных, например, в двоичном формате файла) или требования стандарта битового уровня (сетевые пакеты или опкоды команд).
реальным примером является следующий перенос ядра xnu из архитектуры Motorola 68000 (m68k) в архитектуру i386. Рядом была рабочая версия ядра m68k. Когда они портировали его на i386, они обнаружили, что требования к выравниванию i386 отличаются от требований m68k таким образом, что машина m68k и машина i386 не согласовали макет следующей структуры BOOTP для конкретного поставщика. Чтобы сделать макет структуры i386 согласующимся с m68k, они добавили неназванное битовое поле нулевой длины, чтобы заставить NV1
структура/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;
};
стандарт (9.6/2) допускает только 0 битовых полей длины как особый случай :
как частный случай, неназванный бит-поле с шириной нуля указывает выравнивание следующего битовое поле в единице распределения граница. только при объявлении Безымянное бит-поле может constant-выражение равно значению к нулю.
единственное применение описано в этой цитате, хотя я никогда не сталкивался с этим в практический код.
для записи я просто попробовал следующий код под 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
.
struct X { int : 0; };
неопределенное поведение в C.
посмотреть (выделено мной):
(C99, 6.7.2.1p2) " наличие struct-declaration-list в спецификаторе структуры или объединения объявляет новый тип в единице перевода. Struct-declaration-list-это последовательность объявлений для членов структуры или объединения. если struct-declaration-list не содержит именованных членов, поведение не определено"
(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); }))
Это из MSDN и не помечено как Microsoft Specific, поэтому я думаю, что это общий стандарт C++:
неназванное битовое поле шириной 0 вынуждает выравнивание следующего битового поля к границе следующего типа, где type-тип элемента.
стандарт C11 теперь позволяет включать битовые поля нулевой длины. Вот пример из проекта Комитета C (N1570), который, я считаю, иллюстрирует практическое использование.
3.14 памяти
...
4. Пример структуры, объявленной какstruct { char a; int b:5, c:11, :0, d:8; struct { int ee:8; } e; }
содержит четыре отдельных места памяти: member
a
, и бит-поляd
иe.ee
- отдельные ячейки памяти, и может быть изменены одновременно не мешая друг другу. Битовые поляb
иc
вместе составляют четвертое место памяти. Битовые поляb
иc
невозможно одновременно изменить, ноb
иa
, например, может быть.
таким образом, включая битное поле нулевой длины между битными полями c
и d
позволяет одновременную модификацию b
и d
Как хорошо.