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.

Другие вопросы по тегам