参考或普通C型

时间:2013-07-23 13:44:26

标签: c gcc macros

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

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 *返回X的结果。但是,结果是GCC编译器发出以下警告(取决于X的类型):

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

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

使用

我正在开发一个通用的GPIO配置库(lol)。我认为我有一些相当坚实的东西但显然需要对其他处理器进行更严格的测试。其中一个“金块”是配置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&lt; sizeof(int)(32位ARM处理器)。这里_size是属性描述它的位数。但是,财产可能超出此要求,因此8*_size&gt; sizeof(int)。在这种情况下,属性在内存中占用int[n]空间,并且需要一些额外的数学计算(如上所述)。在我的示例中,af需要4位来描述(5种可能的替代函数可供选择)。对于16个引脚,这变为4 * 16> 1。因此需要int[2]来描述。这美丽和简单,我只需要一个宏来设置GPIO属性的所有

顺便说一下,如果你认为值得,可以随意重复使用。记得给我一点声音!

几个笔记

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

0 个答案:

没有答案