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;
}

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

PAIR ax;

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

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