这是一个挑战问题。我想为可能是数组的未知变量类型创建一个掩码位图。例如,
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
是指针数学的测试。