GNU C замена / обходной путь для typeof / __ auto_type, применяемого к битовым полям - PullRequest
2 голосов
/ 12 июля 2020

GNU C имеет два расширения, которые он предлагает для создания безопасных макросов, таких как MAX и MIN, которые будут оценивать аргументы только один раз: typeof и __auto_type. Приведем примеры двух макросов MAX, демонстрирующих каждый из них:

#define MAX(a, b) ({    \
    typeof(a) _a = (a); \
    typeof(b) _b = (b); \
    _a > _b ? _a : _b;  \
})

#define MAX(a, b) ({      \
    __auto_type _a = (a); \
    __auto_type _b = (b); \
    _a > _b ? _a : _b;    \
})

Проблема с обоими из них в том, что typeof и __auto_type выдают ошибки, если они используются в битовом поле. В этом примере кода показаны проблемы с битовым полем с использованием либо MAX:

#include <stdio.h>
#include <stdint.h>

// Insert one of the MAX macros here

struct bitfields {
    uint8_t a: 4;
    uint8_t b: 4;
};

int main(int argc, char *args[]) {
    struct bitfields x = {12, 4};
    printf("%d\n", MAX(x.a, x.b));
    return 0;
}

G CC дает следующие сообщения об ошибках для typeof и __auto_type соответственно:

error: 'typeof' applied to a bit-field
error: '__auto_type' used with a bit-field initializer

Итак, вопрос: почему G CC не позволяет использовать их с битовыми полями (я не могу найти по нему никакой документации) и что можно сделать, чтобы сделать макрос MAX, который оценивает аргументы только один раз для любого типа, который все еще работает с битовыми полями?

Ответы [ 2 ]

4 голосов
/ 13 июля 2020

Вы используете __typeof__(+(a)), чтобы получить повышенный тип в соответствии с акциями по умолчанию. Это будет работать как минимум для битовых полей типа int. Я не уверен, как компиляторы обрабатывают тип для более крупных типов битовых полей, которые определяются реализацией.

1 голос
/ 12 июля 2020

Эта проблема не имеет приемлемого решения:

Макросы используют расширения c компилятора, такие как typeof или __auto_type, а также выражение ({ ... }), которое не переносимы.

На самом деле они небезопасны по типу a и b имеют разные типы: простое выражение MAX(1L, -1U) даже будет иметь другое значение в зависимости от размера типа long .

Более того, поведение будет неправильным, если выражения, переданные в качестве аргументов, относятся к переменным с именами _a или _b.

Боюсь, что типизированные встроенные функции кажутся лучшим способом переносимость и удобочитаемость, но действительно было бы желательно более универсальное решение c.

РЕДАКТИРОВАТЬ: Я был слишком пессимистичен c: унарный плюс, похоже, помогает для небольших битовые поля.

...