【问题标题】:GCC gives initializer element is not constant, ARMCC does notGCC 给出的初始化元素不是常量,ARMCC 不是
【发布时间】:2020-11-16 12:16:06
【问题描述】:

在 libfixmath 中有the following macro magic:

#define F16C(i, m) \
( (fix16_t) \
    ( \
      (( #i[0] ) == '-') \
        ? -FIXMATH_COMBINE_I_M((unsigned)( ( (i) * -1) ), m) \
        : FIXMATH_COMBINE_I_M((unsigned)i, m) \
    ) \
)

这样用了几十次:

F16C(3,1415)

初始化各种事物,从结构到数组和临时对象。

在 ARMCC 中运行良好。但是我正在迁移到 ARM GCC,它给了我以下错误,但不是在所有实例上,主要是在进行 const 结构初始化时。

error: initializer element is not constant

这与使用非常数作为初始化器有关。这是可以理解的。
但是这个宏被赋予了两个整数字面量。没有比这更稳定的了!

我是否遗漏了什么,或者是否有我不知道的 GCC 扩展来完成这项工作?

更新:macro called by this 中有一个 sizeof(#token)

注意:与 ARMCC 相比,GCC 可以正确解析 F16() 宏并且不会创建 fplib 调用。只是提醒那些将来发现自己遇到此问题的人。

【问题讨论】:

  • 您为什么认为使用? 运算符会产生适合用作初始化程序的常量表达式?
  • 根据godbolt,它works in gcc 8.2但在7.3中失败。
  • @AndrewHenle:因为 C 2018 6.6 6 允许整数常量表达式包含运算符,包括 ? :
  • 宏将i 转换为字符串(#i),然后尝试取其第一个字符(#i[0] 中的[0])。 C 2018 6.6 6 中规定了编译器需要接受的整型常量表达式,不包括使用字符串作为操作数。编译器可能会接受这一点(因为 6.6 10 允许,但不需要它),这可以解释为什么 ARMCC 接受它而旧版本的 GCC 不接受。

标签: c gcc


【解决方案1】:

根据 Godbolt,它 works in gcc 8.2 但在 7.3 中失败。

但是,如果您将( #i[0] ) == '-') 替换为(i) < 0,则它在lower versions too 中有效。

我觉得奇怪的是这个库的作者选择使用( #i[0] ) == '-') 来测试宏参数是否为负,因为如果参数不是整数文字,它将失败。

(更新)根据OP的评论,(i) < 0不能使用的原因是它也需要将-0归类为否定。

以下是 GCC 的一些不同方法:

// does not work on gcc
#define IS_NEG(x) ((#x)[0] == '-')

// works, but fails the "-0" case
#define IS_NEG(x) (x < 0)

// works on gcc (although, it matches '-' at any idx)
#include <string.h>
#define IS_NEG(x) (strchr(#x, '-') != NULL)

奇怪的是,strchr seems to be allowed 在 gcc 5.4 或更高版本上创建编译时常量的用法。

【讨论】:

  • 这很奇怪,需要一些迂回的思考,所以人们不得不怀疑作者除了测试负值之外还有其他想法。
  • 这适用于F16C(-0,5) 吗?此外,它失败了F16C(1,00048)....
  • @Jeroen3:好的,所以负零解释了原因。为什么F16C(1,00048) 会失败?
  • 与八进制有关的事情,是有道理的。这个宏很奇怪....
  • @Jeroen3: 对,所以F16C(1,00048) 调用应该为1.00048 创建一个固定的浮点文字。尽管00048 是八进制文字,但FIXMATH_CONVERT_MANTISSA 的扩展在1 ## m ## ULL 中添加了1,所以我认为在这种情况下它不会失败?
猜你喜欢
  • 2012-06-04
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 2012-04-10
  • 1970-01-01
  • 2014-05-25
相关资源
最近更新 更多