GNU C replacement/workaround for typeof/__auto_type 应用于位字段

GNU C replacement/workaround for typeof/__auto_type applied to bit fields

GNU C 有两个扩展,它建议制作安全的宏,如 MAXMIN,这些宏将只评估一次参数: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;
}

GCC 分别为 typeof__auto_type 给出这些错误消息:

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

所以问题是:为什么 GCC 不允许将这些与位字段一起使用(我找不到任何关于它的文档),以及可以做些什么来制作一个 MAX 评估的宏对于仍可与位字段一起使用的任何类型,仅参数一次?

这个问题有一个简单的可接受的解决方案,使用一元加运算符强制整数提升:

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

然而这种方法有几个问题:

  • 宏使用编译器特定的扩展,例如 typeof__auto_type,以及不可移植的语句表达式 ({ ... })

  • 如果 ab 有不同的类型,它们并不是真正的类型安全:一个简单的表达式 MAX(1L, -1U) 甚至会根据类型的大小 long.

  • 此外,如果作为参数传递的表达式引用名为 _a_b.

    的变量,则行为将不正确

恐怕类型化内联函数似乎是一种更好的可移植性和可读性方式,但确实需要更通用的解决方案。

您使用__typeof__(+(a))根据默认促销获取促销类型。这至少适用于 int 类型的位域。我不确定编译器如何处理更大的位域类型的类型,这些类型是实现定义的。