BUILD_BUG_ON_ZERO не работает в простом приложении пространства пользователя - PullRequest
2 голосов
/ 28 февраля 2020

Я пытался использовать BUILD_BUG_ON_ZERO в простом приложении пользовательского пространства, и он не смог скомпилировать

#include <stdio.h>

#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); }))) 
int main()
{
    int i;
    BUILD_BUG_ON_ZERO(i);
    return 0;
}

error: bit-field ‘<anonymous>’ width not an integer constant
 #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))

Может кто-нибудь дать мне подсказку об ошибке.

Ответы [ 3 ]

1 голос
/ 28 февраля 2020

BUILD_BUG_ON_ZERO используется в коде ядра как утверждение во время компиляции. По сути, он будет проверять, может ли компилятор вычислить аргумент макроса в 0 (во время компиляции) или не выполнить сборку в противном случае.

/*
 * Force a compilation error if condition is true, but also produce a
 * result (of value 0 and type int), so the expression can be used
 * e.g. in a structure initializer (or where-ever else comma expressions
 * aren't permitted).
 */
#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))

Но, как указывает комментарий, он имеет своего рода двойное назначение его также можно использовать как выражение C, например:

#define HWEIGHT64(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight64(w))

Путем поиска по всему коду ядра вы можете обнаружить, что он обычно используется вместе с другими конструкциями, такими как встроенная __builtin_constant_p или __is_constexpr .

1 голос
/ 28 февраля 2020

Как говорит компилятор, ему нужно целочисленное константное выражение. Переменная не является константным выражением.

Но независимо от того, этот макрос не работает.

  • Если вы компилируете на стандартном C компиляторе с BUILD_BUG_ON_ZERO(0), вы получите ошибка "struct не имеет именованных членов", поскольку анонимные битовые поля не являются стандартными C.
  • Если вы компилируете с g cc -std=gnu11 и BUILD_BUG_ON_ZERO(0), вы получите чистый журнал компилятора. Вы не получите ошибку на нуле.
  • Если вы передаете ненулевое значение макросу с помощью стандартного или GNU-компилятора, вы получите ошибку компилятора. Таким образом, цель макроса BUILD_BUG_ON_ZERO состоит в том, чтобы создать ошибку на ненулевой .

При использовании стандартной C вы можете использовать _Static_assert и забыть об этом все, но если вы застряли с расширениями C90 и G CC, рабочий макрос можно записать в виде:

#define ACTUAL_BUILD_BUG_ON_ZERO(e) typedef struct { int cant_have[1-2*!(e)]; } static_assert_t;
  • Если передано ненулевое значение, ! преобразует его в ноль и 1-2*0 = 1, который является допустимым размером для массива.
  • Если передано нулевое значение, ! преобразует его в 1 и 1-2*1 = -1 , который является недопустимым размером для массива.

Это должно быть сделано таким образом, потому что при компиляции как GNU C он все еще поддерживает массивы нулевого размера, как остаток от времени до члены гибкого массива были стандартизированы.

1 голос
/ 28 февраля 2020

Макрос BUILD_BUG_ON_ZERO предназначен для использования с постоянным выражением , как определено в постоянном выражении 6.6 .

i не является константным выражением - это просто локальная переменная. Даже const квалифицированные объекты не считаются «постоянными выражениями» в C (в отличие от C ++). Поэтому вам придется использовать:

  • литеральные значения (такие как 0) или
  • макрос (#define value 0) или
  • использовать enum константа enum { value = 0,};)

для получения константного выражения

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