问题描述
请考虑以下测试代码:
#include <tgmath.h>
void test()
{
double x=cos(4.5);
}
与
一样编译arm-none-eabi-gcc test.c -c
在Ubuntu 18.04(gcc 6.3.1,newlib 2.4.0)上工作正常,但是在Ubuntu 20.04(gcc 9.2.1,newlib 3.3.0)上我遇到以下错误:
In file included from test.c:1:
test.c: In function 'test':
test.c:5:14: error: 'ccosl' undeclared (first use in this function); did you mean 'ccosh'?
5 | double x=cos(4.5);
| ^~~
test.c:5:14: note: each undeclared identifier is reported only once for each function it appears in
test.c:5:14: error: argument 6 of '__builtin_tgmath' is not a function pointer
显然,cos
的定义有所改变,因此现在提到ccosl
,它在任何地方都没有声明。
如果我从tgmath.h
更改为math.h
,该错误将不再出现。当然,这只是解决方法,而不是解决方法,因为这样我就失去了float
和double
的类型通用性。
我的问题是:如何使其正常工作?我是否必须添加一些编译选项,还是仅仅是工具链中的错误?
解决方法
看来,工具链版本之间的差异在于不同版本的tgmath
cos
宏的GCC实现。即,使用-E
的{{1}}选项进行编译会在6.3.1中产生gcc
的以下(已清理)扩展:
double x=cos(4.5)
在GCC 9.3.0中,扩展只是一个简单的函数调用:
double x=__builtin_choose_expr(__builtin_classify_type(4.5) == 9,__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(__real__(4.5)),long double),ccosl(4.5),double) || __builtin_classify_type(__real__(4.5)) == 1,ccos(4.5),ccosf(4.5))
),__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(4.5),cosl(4.5),double) || __builtin_classify_type(4.5) == 1,cos(4.5),cosf(4.5))
)
);
两者之间的主要区别在于double x=__builtin_tgmath (cosf,cos,cosl,ccosf,ccos,ccosl,4.5);
不评估未选择的表达式(如the docs中所述),而__builtin_choose_expr
是一个函数,需要所有参数有效。
而且看起来newlib从未在其__builtin_tgmath
中包含ccosl
,因此它似乎与较新版本的GCC不兼容。