Подтвердить что ты не робот

Практическое использование битовых полей с нулевой длиной

Я не совсем уверен в C, но С++ допускает неназванные битовые поля длиной 0. Например:

struct X
{
    int : 0;
};
  • Вопрос 1. Какое практическое использование этого вы можете придумать?
  • Вопрос второй: Какие практические применения в реальном мире (если есть) вы знаете?

Отредактированный пример после ответа на ледяную преступность

Изменить: Хорошо, благодаря текущим ответам я теперь знаю теоретическую цель. Но вопросы касаются практического использования, поэтому они все еще сохраняют:)

4b9b3361

Ответ 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 является типом элемента.