Что этот дефайн возвращает? Что это за запись?

#define QEMU_BUILD_BUG_ON_STRUCT(x) \
    struct { \
        int:(x) ? -1 : 1; \
    }

Я понимаю что в принципе этот код делает, конкрето ARRAY_SIZE. Но вот этот дефайн выше меня сводит сума

Вот весь стек дефайнов

#define QEMU_IS_ARRAY(x) (!__builtin_types_compatible_p(typeof(x), \
                                                        typeof(&(x)[0])))
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])) + \
                       QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(x)))
#define QEMU_BUILD_BUG_ON_STRUCT(x) \
    struct { \
        int:(x) ? -1 : 1; \
    }
#define QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \
                                   sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))

QEMU_IS_ARRAY возвращает либо 1 либо 0, так ? 1 - значит массив, 0 не массив(В случае если типы не совпадают) QEMU_BUILD_BUG_ON_STRUCT(x) для меня загадка


Ответы (3 шт):

Автор решения: Komdosh

в C if(x) означает: x!=0

x != 0 ? -1 : 1;

QEMU_BUILD_BUG_ON_STRUCT(1) вернёт структуру с переменной int,

{
 int: -1; //-1 - если x != 0 и 1 если x == 0
}
→ Ссылка
Автор решения: Fat-Zer

Это очень сильное колдунство... (c) какой-то опер

Что это делает

  • QEMU_BUILD_BUG_ON, согласно имени, должен вызывать ошибку компиляции, если ей передано истинной значение.
  • QEMU_BUILD_BUG_ON_ZERO — аналогично, но также она должна предстовлять собой выражение с нулевым значением, т.е. по факту это static_assert, возвращающий 0.
  • QEMU_BUILD_BUG_ON_STRUCT — просто служебный макрос с помощью которого и реализован QEMU_BUILD_BUG_ON_ZERO

Как это работает

QEMU_BUILD_BUG_ON_STRUCT раскрывается в определение анонимной структуры с безымянным битовым полем:

struct {
    int:(x) ? -1 : 1;
}

Или если добавить имена:

struct foo {
    int bar:(x) ? -1 : 1;
}

Если значение выражения x равно 0, то битовое поле определяется со значением 1 и структура является корректно объявленной.

В противном случае структура оказывается определённой с битовым полем отрицательной длины (-1), что вызывает ошибку.

QEMU_BUILD_BUG_ON_ZERO(x) — это просто выражение с нулевым значением (n-n); если n корректно (x истинно и определение структуры в QEMU_BUILD_BUG_ON_STRUCT не вызывает ошибку компиляции), то это равносильно следующему:

sizeof(struct {int :1;}) - sizeof(struct {int :1;})

В противном случае оно, само собой, просто вызывает ошибку компиляции.

Так изощряться пришлось, чтобы впихнуть проверку времени компиляции прямо в определение ARRAY_SIZE и оно ничего не испортило.

→ Ссылка
Автор решения: user7860670

При определении размера массива обычным способом sizeof(x) / sizeof((x)[0]) крайне легко прострелить себе ногу, когда x не является массивом, а является указателем. Соответственно QEMU_BUILD_BUG_ON_STRUCT работает по аналогии со static_assert - если срабатывает условие !QEMU_IS_ARRAY(x), то будет объявлена структура с битовым полем меньше нуля, что вызовет ошибку времени компиляции.

int * not_arr = NULL;
size_t size = QARRAY_SIZE(not_arr); // error
→ Ссылка