C Глобальная переменная с тем же именем, что и системная функция, вызывает segfault? - PullRequest
0 голосов
/ 28 февраля 2019

Рассмотрим эту чрезвычайно простую настройку:

Содержимое файла foo.c:

#include "bar.h"

int socket[128];

int main(int argc, char *argv[])
{
        bar();

        return 0;
}

Содержимое bar.h

void bar(void);

Содержимое bar.c:

#include <sys/socket.h>

void bar(void)
{
        socket(AF_INET,SOCK_DGRAM,0);
}

Компиляция:

gcc -Wall -pedantic foo.c bar.c -o foobar

Запуск

./foobar

Когда эта программа компилируется и связывается без ошибок, и при запуске она вызывает ошибку сегментации ввызов функции socket () в bar.c.Изменение имени глобальной переменной в foo.c на что-то отличное от «socket» исправляет это.Но я не понимаю почему ?Разве это не должно быть ошибкой компоновщика по крайней мере?

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Обычным поведением компоновщиков является извлечение объектного модуля из библиотеки тогда и только тогда, когда этот модуль определяет символ, который используется, но не разрешен в создаваемом исполняемом файле.

Это важно и необходимоповедение, чтобы избежать конфликтов между символами в программах и символами в библиотечных модулях, которые автор не использовал.В более поздних языках, таких как C ++, эта проблема решалась путем разделения пространств имен (например, std::).Но, как правило, нам приходится иметь дело с тем фактом, что многие авторы естественным образом используют имена для своих собственных подпрограмм или объектов, таких как read или write, которые конфликтуют с подпрограммами библиотеки.Линкеры должны это разрешать.

Итак, когда ваша программа определяет socket, компоновщик разрешает это определение и не берет его из библиотеки.Компоновщик не знает, что код в одном из ваших модулей использует socket как функцию, в то время как определение в другом модуле относится к объекту.

0 голосов
/ 28 февраля 2019

socket - указатель на массив.

Из другого файла вы считаете socket указателем на функцию ср.объявление socket.h.

компоновщик может связать их, потому что компоновщик не знает типов .

У вас должен быть общий заголовок, в котором вы объявляетеэкспортированные символы, чтобы поймать такие вещи.

Если компоновщик найдет символ socket в библиотеке, которую вы используете при компоновке, он вставит адрес этого.В противном случае он будет связываться с socket из библиотеки posix системы.

...