c – не может принимать адрес битового поля

Почему не удается получить адрес битового поля?

Как сделать указатель на бит-поле?

Вот код …

struct bitfield { unsigned int a: 1; unsigned int b: 1; unsigned int c: 1; unsigned int d: 1; }; int main(void) { struct bitfield pipe = { .a = 1, .b = 0, .c = 0, .d = 0 }; printf("%d %d %d %d\n", pipe.a, pipe.b, pipe.c, pipe.d); printf("%p\n", &pipe.a); /* OPPS HERE */ // error: cannot take address of bit-field ... return 0; } 

    Элементы битполей (как правило) меньше, чем гранулярность, разрешенная указателями, что является зернистостью char s (по определению char , который, кстати, должен иметь минимум 8 бит). Таким образом, обычный указатель не режет.

    Кроме того, неясно, каким будет тип указателя на член битового поля, поскольку для хранения / извлечения такого элемента компилятор должен точно знать, где он находится в битовом поле (и нет «обычного» типа указателя несут такую ​​информацию).

    Наконец, это едва ли запрошенная функция (битпоны часто не видны на первом месте); битовые поля используются для компактного хранения информации или для создания упакованного представления флагов (например, для записи на аппаратные порты), редко бывает, что вам нужен указатель на одно поле из них, и если это необходимо, вы всегда можете прибегнуть к регулярному struct и преобразовать в битполе в последний момент.

    По всем этим причинам стандарт говорит, что члены битовых полей не адресуются, период. Было бы возможно преодолеть эти препятствия (например, путем определения специальных типов указателей, которые хранят всю информацию, необходимую для доступа к члену битового поля), но это был бы еще один сложный темный угол языка, который никто не использует.

    У вас не может быть адрес битового поля, потому что наименьшее адресуемое устройство является байтом (помня, что байты в C могут не быть шириной 8 бит).

    Лучшее, на что можно надеяться, это адрес содержательной структуры.

    Соответствующей частью стандарта (C11) является раздел 6.5.3.2 Address and indirection operators (курсив мой):

    Операнд унарного оператора & должен быть либо обозначением функции, результатом оператора [] либо унарного * , либо значением lvalue которое обозначает объект, который не является битовым полем и не объявлен с помощью спецификатора classа хранения регистров ,

    Учитывая, что наименьшая адресуемость – это байт, и вы можете найти сжатые таким образом битфилы:

     Addr\Bit 7 6 5 4 3 2 1 0 00001234 | a | b | c | d | ? | ? | ? | ? | 00001235 | | | | | | | | | 

    вы можете видеть, что адрес всех этих битфайлов на самом деле один и тот же, поэтому на самом деле это не так полезно.

    Для управления битфилдами вам действительно нужно просто получить к ним доступ напрямую и позволить компилятору разобраться в них. Даже использование побитовых операторов не гарантируется, если вы не знаете, как компилятор их выкладывает в памяти.

    Адреса должны быть целым числом байтов, но бит-поля не обязательно должны быть, поэтому в стандарте C указывается, что адресный оператор & не может использоваться с ними. Конечно, если вы действительно хотите делать что-то с адресами битовых полей, вы можете просто использовать адрес входящей структуры с некоторыми побитовыми операциями.

    на аналогичной ноте, если вы просто хотите адресовать отдельные байты, вы можете сделать что-то вроде этого:

     union PAIR { struct { uint8_t l, h; } b; uint16_t w; }; PAIR ax; 

    теперь вы можете получить доступ к указателям на части типа & ax.w, & ax.bl или & ax.bh, но это не позволяет указывать на отдельные биты, см. предыдущие объяснения об этом.

    EDIT: фиксированный пример