На странице 14 книги «Введение в GCC» автора Брайан Гоф автор хочет показать ошибку компоновщика из-за того, что gcc не предоставил библиотеку libm
, где находится код функции sqrt
:
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sqrt’
Файл calc.c
(где вызывается функцияsqrt
) таков:
#include <math.h>
#include <stdio.h>
int main (void)
{
double x = sqrt (2.0);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
Эта книга 2003 года. В моей текущей Ubuntu Linux 18 я не могу воспроизвести ошибку ссылки: она связывается и работает, печатая правильный результат:
$ ./calc
1.414214
С помощью ldd calc
я обнаружил, что общая библиотека libm.so
не вызывается во время выполнения. И, конечно же, здесь не задействована статическая библиотека libm.a
.
Так как же gcc справляется с функцией sqrt
? Я обнаружил, что в этом случае используется sqrt
Встроенная функция GCC.
Его код вставляется в объектный файл calc.o
во время компиляции. Так что нет ошибки «неопределенная ссылка».
Первый вопрос: это все или я что-то упустил?
Второй вопрос: почему поведение встроенных функций GCC так сильно изменилось между 2003 годом (когда была написана книга) и сейчас? (Мне кажется, что практически обесценивает весь пример)
Третий вопрос: почему автор делает свои примеры (например, $ gcc -Wall calc.c -lm -o cal
), подразумевая, что будет использоваться статическая библиотека libc.a
, когда на самом деле в Linux этот синтаксис вызывает динамическую библиотеку libm.so
? Это относится к Linux, а не к GNU GCC? Что мне не хватает?
Я думаю, это связано с оптимизацией постоянного значения. Современный GCC может вычислить точное значение sqrt (2.0)
. Если вы заставите его не использовать встроенные модули с помощью -fno-builtin
, он все равно не сможет связать. Кроме того, если вы немного измените код, чтобы аргумент sqrt()
не был буквальным, он не сможет связать:
#include <math.h>
#include <stdio.h>
double t = 2.0;
int main (void)
{
double x = sqrt (t);
printf ("The square root of 2.0 is %f\n", x);
return 0;
}
Это приводит к ошибке ссылки:
> gcc -o test test.c
/usr/bin/ld: /tmp/ccLjHnQx.o: in function `main':
test.c:(.text+0x11): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
Что касается вашего третьего вопроса, -lm
не подразумевает статическую библиотеку, насколько я знаю.
Большое спасибо! Значит, в 2003 году оптимизация постоянного значения в GCC еще не проводилась, верно? Что вы думаете о моем третьем (немного не связанном) вопросе? Мне любопытно...
Потому что 15 лет — это много времени.