ccosl необъявлен при попытке использовать cos(double) из tgmath.h на arm-none-eabi-gcc
Рассмотрим следующий тестовый код:
#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
.
У меня вопрос: как заставить его работать правильно? Нужно ли мне добавлять какие-то опции компиляции или это просто ошибка в инструментальной цепочке?
1 ответ
Похоже, что разница между версиями инструментальных средств заключается в реализации GCC: tgmath
cos
макрос в разных версиях. А именно компиляция с-E
вариант для gcc
дает следующее (очищенное) расширение double x=cos(4.5)
в 6.3.1:
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),
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(__real__(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), long double),
cosl(4.5),
__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(4.5), double) || __builtin_classify_type(4.5) == 1,
cos(4.5),
cosf(4.5))
)
);
в то время как в GCC 9.3.0 расширение представляет собой простой вызов функции:
double x=__builtin_tgmath (cosf, cos, cosl, ccosf, ccos, ccosl, 4.5);
Основное различие между ними в том, что __builtin_choose_expr
не оценивает выражение, которое не выбрано (как сказано в документации), а__builtin_tgmath
- это функция, для которой необходимо, чтобы все аргументы были действительными. И похоже, что в newlib никогда не былоccosl
в его complex.h
, поэтому он несовместим с новой версией GCC.