【问题标题】:C Macro: get smallest type for an integer constantC宏:获取整数常量的最小类型
【发布时间】:2017-11-05 18:02:48
【问题描述】:

为什么我需要找出字面量的 smalles 类型(背景故事)

我编写了一组宏来创建和使用 fifo。宏允许在所有具有静态内存分配的系统上进行通用但仍然非常快速的实现,例如在小型嵌入式系统中。 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),如果 arguint16_t 否则返回 uint8_t

我尝试过的

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

你就不能这样吗?

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

【问题讨论】:

  • 这似乎是 C++ 模板的理想用例,但我知道您的问题与 C++ 无关。
  • @GregHewgill 如果所有常量都是 int 类型,那么在 C 中真正有什么帮助...
  • 以下划线开头的名称保留用于文件范围内的实现。而且空的初始化列表是非法的。

标签: c gcc casting macros c-preprocessor


【解决方案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++ 有更好的工具(但它们仍然难以使用)。

【讨论】:

  • 在小型微控制器上没有足够的资源来有效地运行 C++。幸运的是,这个解决方案运行良好,最终代码在我下面的答案中。感谢您的提示!
【解决方案2】:

我正在寻找的宏确实可以用__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)))))

【讨论】:

  • 我不知道为什么这个答案被否决为 0。这个答案是可靠的。谢谢你提供它。我刚刚将您的答案从 0 投票到 1。
猜你喜欢
  • 2015-05-26
  • 2023-04-05
  • 1970-01-01
  • 2015-10-28
  • 2012-01-29
  • 1970-01-01
  • 2016-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多