#c #libc
#c #libc
Вопрос:
Предположим, что используется следующий простой C
код:
file1.c
#include <stdio.h>
char* gets(char* i){
return i;
}
которое переопределяет собственную функцию libC gets
.
Это отлично компилируется с gcc file1.c
.
Мой вопрос в том, почему компоновщик не жалуется на duplicate symbols
, поскольку эта функция также определена в самой libC?
Комментарии:
1. Примечание:
gets()
отсутствует в стандартной библиотеке C11 / C17.2. компоновщик @chux предупреждает с помощью
warning: the
получения ‘функция опасна и ее не следует использовать` при ее использовании. Я использую C11.3. Алекс, обязательно попробуй
gcc -std=c11 -Wall -Wextra -Wconversion file1.c
4. предупреждение — это другой вопрос и связано с защитой от переполнения
5. предупреждение о
gets()
НЕ о защите от переполнения, а скорее о функцииgets()
, которая годами устаревала и была полностью удалена в последних двух версиях языка программирования C.
Ответ №1:
Поскольку в C можно переопределять функции из стандартных библиотек, проверьте это
Комментарии:
1. Переопределение функций стандартной библиотеки — это неопределенное поведение, хотя оно часто (но не всегда) «работает так, как ожидалось». Смотрите раздел 7.1.3 (Зарезервированные идентификаторы) стандарта C, в частности параграф 2.
Ответ №2:
добавьте опцию -весь архив на этапе компоновки, как показано ниже:
gcc -c -ofile1.o file1.c
gcc -ofile1 -Wl,--whole-archive -lc file1.o -Wl,--no-whole-archive
Результат:
file1.o: In function `gets':
file1.c:(.text 0x0): multiple definition of `gets'
file1.o: In function `main':
file1.c:(.text 0x18): undefined reference to `gets@@GLIBC_2.2.5'
collect2: error: ld returned 1 exit status
Ответ №3:
Вы столкнулись с неопределенным поведением, см. N1570 6.9(p5) External definition
:
Если идентификатор, объявленный с внешней привязкой, используется в выражении (кроме как как часть операнда оператора
sizeof
or_Alignof
, результатом которого является целочисленная константа), где-то во всей программе должно быть ровно одно внешнее определение идентификатора; в противном случае их должно быть не более одного.161)
Как можно видеть. Стандарт допускает 2 возможности:
- ровно одно определение
- не более одного определения.
Это может зависеть от привязки, libc
которая сама по себе зависит от системы. В случае, если вы связываете libc
статически, компоновщик будет жаловаться. В случае динамической компоновки у него нет причин жаловаться.
Если вы взглянете на, objdump
вы найдете plt
раздел, подобный
898: e8 b3 fe ff ff callq 750 <gets@plt>
В любом случае поведение не определено.