首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重写GCC的varargs参数提升

重写GCC的varargs参数提升
EN

Stack Overflow用户
提问于 2019-10-01 13:48:31
回答 1查看 235关注 0票数 4

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

代码语言:javascript
复制
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)
}

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

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

EN

回答 1

Stack Overflow用户

发布于 2019-10-01 14:56:50

将vararg float参数转换为double不是gcc的怪癖,也不是附加功能。这是C标准所要求的。§6.5.2.3 (函数调用):

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

上执行缺省参数提升

Gcc确实提供了一些与C标准不兼容的选项,但绝大多数选项仅在标准无法做到这一点的情况下添加行为。如此巨大的变化将影响标准调用约定,使编译后的代码与其他编译代码不兼容,如库、标准或其他。Gcc并没有提供这样的选项。其他编译器可能会,但我不知道有哪一个是这样做的。

请注意,在标准的约束下,如果double是32位的值,则不可能仅将float作为float的同义词。§5.2.4.2.2中的最低精度要求有效地要求双精度除指数和符号外,至少还有一个32位的尾数。这比64位IEEE-749 doubles提供的精度要低得多,但显然比32位值提供的精度要高。

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

不过,我不相信GCC也提供了这种选择。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58178731

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档