0

这是一个挑战问题。我想为可能是数组的未知变量类型创建一个掩码位图。例如,

char ch;
int i;
int i_arr[2];

printf("The ordinary type for ch is %lu bytes.\n", sizeof(ORDINARY_TYPE(ch)));
printf("The ordinary type for i is %lu bytes.\n", sizeof(ORDINARY_TYPE(i)));
printf("The ordinary type for i_arr is %lu bytes.\n", sizeof(ORDINARY_TYPE(i_arr)));

输出应该是:

The ordinary type for ch is 1 bytes.
The ordinary type for i is 4 bytes.
The ordinary type for i_arr is 4 bytes.

听起来不可能?它不是。为了让您快速开始,我将提供我的“解决方案” - 请注意,它是非常特定于 GCC 的,尽管我想知道是否可以将内置函数重写为与编译器无关。

#define IS_PTR(X) \
    __builtin_choose_expr( \
        __builtin_types_compatible_p(typeof(X), char*), \
        1, \
    __builtin_choose_expr( \
        __builtin_types_compatible_p(typeof(X), int8_t*), \
        1, \
    __builtin_choose_expr( \
        __builtin_types_compatible_p(typeof(X), uint8_t*), \
        1, \
        (((uintptr_t)((1 ? (X) : (uintmax_t)0)+1) - \
                (uintptr_t)(1 ? (X) : (uintmax_t)0)) != 1)? 1 : 0 \
    )))

#define ORDINARY_TYPE(X)    \
    typeof(* __builtin_choose_expr( \
        __builtin_types_compatible_p( \
            typeof(*(IS_PTR(X)? (X) : (&(X)))), void), \
                ((X)), \
                (&(X)) \
    ))

在这里,我利用了IS_PTR(X)? (X) : (&(X))返回void *ifX是指针的结果。然而,结果,GCC 编译器会给出以下警告(取决于 的类型X):

warning: pointer/integer type mismatch in conditional expression [enabled by default]
warning: pointer type mismatch in conditional expression [enabled by default]

任何人都可以在没有收到这些警告的情况下做到这一点并使其“更友好”吗?

利用

我正在开发一个通用的 GPIO 配置库(大声笑)。我认为我有一些相当可靠的东西,但显然它需要对其他处理器进行更严格的测试。“金块”之一是配置 GPIO 引脚的属性,

CPU_GPIO_CONFIG_PROP(gpio, pupd, 2);  // Pull up/down, Open Drain, or none
CPU_GPIO_CONFIG_PROP(gpio, af,   4);  // Alternative Functions

CPU_GPIO_CONFIG_PROP像这样定义的地方,

extern struct cpu_gpio;
#define CPU_GPIO_CONFIG_PROP(_gpio, _prop, _size) ({ \
    struct cpu_gpio *bus = (_gpio)->bus_addr; \
    ORDINARY_TYPE( ((struct cpu_gpio *) 0)->_prop) prop_type; \
    const size_t prop_size = sizeof(prop_type); \
    const unsigned short pin = ((_size)*(_gpio)->pin) % (8*prop_size); \
    const typeof(prop_type) mask = ~(~((typeof(prop_type)) 0x0) << _size); \
    typeof(prop_type) *p = ((typeof(prop_type) *) &bus->_prop \
        + ((_size)*((_gpio)->pin)/(8*prop_size))); \
    *p = (*p & ~(mask << pin)) | (((typeof(prop_type)) gpio->_prop) << pin); \
})

呸!好吧,有人又要问“为什么?” (@nneonneo)...简单的答案(因为这太长了)是每个 GPIO 属性通常8*_size< sizeof(int)(32 位 ARM 处理器)。这_size是该属性用来描述它的位数。但是,属性有可能超过此要求,因此采用8*_size> sizeof(int)。在这种情况下,该属性会占用int[n]内存空间,并且需要一些额外的数学来计算(正如我在上面所做的那样)。在我的示例中,af需要 4 位来描述(5 个可能的替代函数可供选择)。对于 16 个引脚,这变为 4*16 > 32,因此需要int[2]进行描述。GPIO 属性!

顺便说一句,如果您觉得值得,请随时重复使用。只要记得给我一点喊声!

几个笔记

  • 这不适用于void*, intXX_t **(或任何引用多个指针的指针,因此&(int[n])即使(void *)ARR == (void *)&ARR)。
  • __builtin_types_compatible_p(typeof(char), int8_t, ...)评估为假。
  • (uintptr_t)((X)+1) - (uintptr_t)(X) != 1是指针数学的测试。
4

0 回答 0