The*_*mer 6 c gcc variadic-functions
我正在为运行 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)
}
Run Code Online (Sandbox Code Playgroud)
更新:根据要求,我想要使用的呼叫命令是myprintf("%f", 1.0f);
。问题是 Cortex-M4 不支持双精度,因此当 1.0f 提升为双精度时......好吧,它不能。因此,使用它将va_arg(args, double)
编译但不会链接,因为__aeabi_
与双精度相关的各种函数不存在。我想要做的是禁用 GCC 将浮点数提升为双精度(如果可能)。
更新:我有一个当前的解决方法,基本上只接受指向浮点数而不是浮点数的指针。我仍然想禁用促销,因为这不是一个很好的解决方案。
将 varargfloat
参数转换为double
不是 gcc 的怪癖或附加组件。这是C标准所要求的。§6.5.2.3(函数调用):
\n\n\n\n
\n- 如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并且具有类型的参数
\nfloat
将提升为double
。这些称为默认参数促销。\xe2\x80\xa6- 如果表示被调用函数的表达式具有包含原型的类型,则参数会像通过赋值一样隐式转换为相应参数的类型,并将每个参数的类型作为其声明的非限定版本类型。函数原型声明符中的省略号表示法会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是对尾随参数执行的。
\n
Gcc 确实提供了一些与 C 标准不兼容的选项,但绝大多数仅在标准无法这样做的情况下添加行为。这种程度的变化会影响标准调用约定,使编译后的代码与其他编译后的代码(例如库、标准或其他代码)不兼容。Gcc 不提供这样的选项。其他编译器可能会这样做,但我不知道哪个编译器会这样做。
\n\n请注意,在标准的限制范围内,不可能仅为if is a 32 位值创建double
同义词。§5.2.4.2.2 中的最低精度要求实际上要求除指数和符号外,双精度数还至少具有 32 位尾数。这比 64 位 IEEE-749 双精度提供的精度要低很多,但显然比 32 位值所能提供的精度要高。float
float
编译器当然可以提供一个选项,其中double
s 以不太精确且计算速度更快的格式表示,例如float
尾数不重叠的两个 s。(也就是说,指数至少在尾数的宽度上有所不同。)这种表示或类似的东西至少被一个遗留实现 IIRC 使用,正是因为它允许使用单精度硬件进行双精度计算。这也使得铸造 afloat
变得double
微不足道;只需将低位值设置为0.0即可。或者,编译器可以使用 32 位尾数与short
指数相结合,从而允许使用整数 ALU。
不过,我也不认为 GCC 提供了这种替代方案。
\n