我正在为运行Cortex-M4架构的ARM处理器编写一段代码(具有单精度浮点数,但不具有双精度浮点数)。我遇到的问题是在使用varargs时,编译器试图将浮点数提升为双精度浮点数。有什么办法可以把它关掉吗?或者指定不同的促销策略?我看了一下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)
}更新:根据请求,我希望使用的call命令是myprintf("%f", 1.0f);。问题是Cortex-M4不支持double,所以当1.0f升级到double...但是它不能,所以使用va_arg(args, double)读回它可以编译,但不会链接,因为与doubles相关的各种__aeabi_函数不存在。我想做的是禁止GCC将浮点数提升为双精度(如果可能的话)。
更新:我目前有一个变通方法,基本上只接受指向浮点数的指针,而不是浮点数。我仍然想禁用促销,因为这不是一个很好的解决方案。
发布于 2019-10-01 14:56:50
将vararg float参数转换为double不是gcc的怪癖,也不是附加功能。这是C标准所要求的。§6.5.2.3 (函数调用):
float的参数提升为double。这些被称为默认参数提升。…上执行缺省参数提升
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也提供了这种选择。
https://stackoverflow.com/questions/58178731
复制相似问题