【问题标题】:Override GCC's varargs argument promotion覆盖 GCC 的 varargs 参数提升
【发布时间】:2023-03-25 19:24:02
【问题描述】:

我正在为运行 Cortex-M4 架构(具有单精度浮点但不是双精度)的 ARM 处理器编写一段代码。我遇到的问题是在使用可变参数时,编译器试图将我的浮点数提升为双精度数。有什么办法可以关闭它吗?还是指定不同的促销策略?我查看了 GCC 手册,但找不到任何东西。一个简单的例子是尝试编写自己的 printf...

void myprintf(const char *fmt, ...) {
  // .. parse fmt and come across %f

  double dv = va_arg(args, double); // Compiles but doesn't link

  float fv = va_arg(args, float); // Doesn't compile (warns about promotion)
}

更新:根据要求,我希望使用的调用命令是myprintf("%f", 1.0f);。问题是 Cortex-M4 不支持双精度,所以当 1.0f 提升为双精度时……它不能。因此,使用va_arg(args, double) 将其读回将编译但不会链接,因为与双精度相关的各种__aeabi_ 函数不存在。我想要做的是禁用 GCC 将浮点数提升为双精度数(如果可能的话)。

更新:我有一个当前的解决方法,基本上只接受指向浮点数而不是浮点数的指针。我仍然想禁用促销,因为这不是一个很好的解决方案。

【问题讨论】:

  • 请说明你是怎么称呼它的。也许使用正确的浮点数(例如1.0f 而不是1.0)会有所帮助。
  • 也许是 float arg 的包装器以使用复合文字 ((float){arg}) 然后传递复合文字的地址?
  • 如果目标处理器不支持双精度,为什么编译器不知道这一点?
  • 不应该只是实现double作为float的同义词吗?
  • 我同意“应该”,但事实并非如此。使用当前解决方法更新问题

标签: c gcc variadic-functions


【解决方案1】:

将 vararg float 参数转换为 double 不是 gcc 怪癖或附加组件。它是 C 标准所要求的。 §6.5.2.3(函数调用):

  1. 如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升,并且类型为float 的参数提升为double。这些被称为默认参数提升。 …
  2. 如果表示被调用函数的表达式具有包含原型的类型,则参数将隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为非限定版本其声明的类型。函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。 默认参数提升是在尾随参数上执行的。

Gcc 确实提供了一些与 C 标准不兼容的选项,但绝大多数仅在标准不这样做的情况下才添加行为。这种幅度的变化会影响标准调用约定,使编译的代码与其他编译的代码(如库、标准或其他)不兼容。 Gcc 不提供这样的选项。其他编译器可能,但我不知道有哪个。

请注意,在标准的约束下,如果float 是一个 32 位值,则不可能只使double 成为float 的同义词。 §5.2.4.2.2 中的最低精度要求实际上要求双精度数除指数和符号外至少有一个 32 位尾数。这比 64 位 IEEE-749 双精度提供的精度要低得多,但显然超过了 32 位值所能提供的精度。

编译器当然可以提供一个选项,其中doubles 以不太精确且计算速度更快的格式表示,例如尾数不重叠的两个floats。 (也就是说,指数至少相差尾数的宽度。)该表示或类似的东西被至少一个遗留实现 IIRC 使用,正是因为它允许单精度硬件用于双精度计算.它还使得将float 转换为double 变得微不足道;只需将低阶值设为 0.0。或者,编译器可以使用 32 位尾数和 short 指数,这允许使用整数 ALU。

不过,我认为 GCC 也不提供这种替代方案。

【讨论】:

  • C 标准无关紧要。该问题不要求 C 标准解决方案。它要求 GCC 解决方案。 GCC 已经实现了与 C 标准不同的各种行为,而不是对其的扩展。这只是一个。 (GCC 开关的每种组合构成不同的 C 实现。其中一些符合 C 标准、模数错误和其他缺陷。其中一些不符合。)
  • 我必须在这里同意,因为我正在寻找相同的解决方案,有一个很好的理由 - 我需要能够传递浮点数而不是双精度数,并且我控制从 _start 到的整个环境结束。让我们找到解决方案!
猜你喜欢
  • 2014-04-05
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 2020-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多