C宏:获取整数常量

时间:2017-11-05 18:02:49

标签: c gcc casting macros c-preprocessor

为什么我需要弄清楚文字的较小类型(Backstory)

我已经编写了一组宏来创建和使用fifos。宏允许在具有静态内存分配的所有系统上实现通用但仍然非常快速的实现,例如在小型嵌入式系统中。在codereview上的那些人对my implementation也没有任何重大担忧。

将数据放入匿名struts中,所有数据都由该结构的标识符访问。目前,用于创建这些结构的类似函数的宏看起来像这样

#define _fff_create(_type, _depth, _id)                 \
    struct {uint8_t read; uint8_t write; _type data[_depth];} _id = {0,0,{}}

#define _fff_create_deep(_type, _depth, _id)            \
    struct {uint16_t read; uint16_t write; _type data[_depth];} _id = {0,0,{}}

我正在寻找什么

现在我想将这两者合并为一个宏。为此,我要在编译时计算readwrite的最小所需大小,以便在编译时索引_depth个元素。以_开头的参数名称仅表示可以传递文字或#define值,两者都在编译时已知。

因此,我希望找到一个宏typeof_literal(arg),如果arg <256或uint8_t,则返回uint16_t

我尝试了什么

  1. GCC 4.9.2。提供名为typeof()的命令。但是,当与任何文字一起使用时,它会返回int类型,这是我系统上的两个字节。
  2. GCC 4.9.2的另一个特点是compound statementtypeof(({uint8_t u8 = 1; u8;}))将正确返回uint8_t。但是我无法想出一种方法来为该块中的类型设置条件:
  3. 由于?:运算符的类型提升,
  4. typeof(({uint8_t u8 = 1; uint16_t u16 = 1; input ? u8 : u16;}))始终返回uint16_t
  5. if(...)也无法使用,因为任何命令都会在&#34; lower&#34;块
  6. 宏不能包含#if,这使得它们无法用于此比较。
  7. 你不能这样离开吗?

    我意识到可能没有解决这个问题的方法。那也没关系;目前的代码只是一个小小的不便。然而,我想知道这是否是一个棘手的方法。解决方案可以为宏开辟新的可能性。如果您确定无法做到这一点,请解释原因。

2 个答案:

答案 0 :(得分:1)

我认为您正在寻找的构建块是__builtin_choose_expr,它与三元运算符非常相似,但不会将其结果转换为常见类型。与

#define CHOICE(x) __builtin_choose_expr (x, (int) 1, (short) 2)

printf ("%zu %zu\n", sizeof (CHOICE (0)), sizeof (CHOICE (1)));

将打印

2 4

正如所料。

然而,正如Greg Hewgill指出的那样,C ++有更好的设施(但它们仍然难以使用)。

答案 1 :(得分:1)

我正在寻找的宏确实可以用__builtin_choose_expr编写为Florian建议。我的解决方案附在下面,经过测试并确认有效。按你的意愿使用它!

#define typeof_literal(_literal)                                                        \
    typeof(__builtin_choose_expr((_literal)>0,                                          \
        __builtin_choose_expr((_literal)<=UINT8_MAX, (uint8_t) 0,                       \
        __builtin_choose_expr((_literal)<=UINT16_MAX, (uint16_t) 0,                     \
        __builtin_choose_expr((_literal)<=UINT32_MAX, (uint32_t) 0, (uint64_t) 0))),    \
        __builtin_choose_expr((_literal)>=INT8_MIN, (int8_t) 0,                         \
        __builtin_choose_expr((_literal)>=INT16_MIN, (int16_t) 0,                       \
        __builtin_choose_expr((_literal)>=INT32_MIN, (int32_t) 0, (int64_t) 0)))))