Может ли GCC не жаловаться на неопределенные ссылки? - PullRequest
49 голосов
/ 05 апреля 2011

При какой ситуации GCC может не выдавать сообщение об ошибке ссылки «неопределенная ссылка» при попытке вызвать составленные функции?

Например, ситуация, в которой этот код на C компилируется и связывается GCC:

void function()
{
    made_up_function_name();
    return;
}

... даже если made_up_function_name отсутствует в любом месте в коде (не заголовках, исходных файлах, объявлениях или какой-либо сторонней библиотеке).

Может ли такой код быть принят и скомпилирован GCC при определенных условиях, не затрагивая фактический код? Если да, то что?

Спасибо.

РЕДАКТИРОВАТЬ: никаких предыдущих заявлений или упоминаний made_up_function_name больше нигде нет. Это означает, что grep -R всей файловой системы будет только показывать эту единственную строку кода.

Ответы [ 7 ]

83 голосов
/ 05 апреля 2011

Да, можно избежать сообщения о неопределенных ссылках - используя параметр компоновщика --unresolved-symbols.

g++ mm.cpp -Wl,--unresolved-symbols=ignore-in-object-files

С man ld

- неразрешенные-символы = метод

Определите, как обрабатывать неразрешенные символы. Есть четыре возможные значения для метода:

       ignore-all
           Do not report any unresolved symbols.

       report-all
           Report all unresolved symbols.  This is the default.

       ignore-in-object-files
           Report unresolved symbols that are contained in shared
           libraries, but ignore them if they come from regular object
           files.

       ignore-in-shared-libs
           Report unresolved symbols that come from regular object
           files, but ignore them if they come from shared libraries.  This
           can be useful when creating a dynamic binary and it is known
           that all the shared libraries that it should be referencing
           are included on the linker's command line.

Поведение для совместно используемых библиотек также может быть управляется параметром - [no-] allow-shlib-undefined.

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

3 голосов
/ 05 апреля 2011

Если вы объявите прототип функции перед ее использованием, она будет скомпилирована. В любом случае ошибка при связывании останется.

void made_up_function_name();
void function()
{
    made_up_function_name();
    return;
}
2 голосов
/ 22 июля 2014

TL; DR Это может не жаловаться, но вы не хотите этого. Ваш код потерпит крах, если вы заставите компоновщик игнорировать проблему. Это было бы контрпродуктивно.

Ваш код опирается на древний C (до C99), позволяющий неявно объявлять функции в точке их использования. Ваш код семантически эквивалентен следующему коду:

void function()
{
    int made_up_function_name(...); // The implicit declaration

    made_up_function_name(); // Call the function
    return;
}

Компоновщик справедливо жалуется, что объектный файл, содержащий скомпилированный function(), ссылается на символ, который больше нигде не был найден. Вы должны исправить это с помощью , обеспечив реализацию для made_up_function_name() или удалив бессмысленный вызов . Это все, что нужно. Никаких компоновок.

2 голосов
/ 12 июля 2012

И затем возникает эта неприятность с флагом -D, переданным в GCC.

$cat undefined.c
void function()
{
    made_up_function_name();
    return;
}


int main(){
}

$gcc undefined.c -Dmade_up_function_name=atexit
$

Просто представьте себе, что вы ищете определение made_up_function_name - оно нигде не появляется, но "делает вещи" в коде. Я не могу придумать вескую причину, чтобы сделать именно это в коде.

Флаг -D - мощный инструмент для изменения кода во время компиляции.

1 голос
/ 16 сентября 2016

При сборке с флагом компоновщика -r или --relocatable он также не будет выдавать никаких сообщений об ошибке ссылки "неопределенная ссылка".

Это связано с тем, что -r свяжет различные объекты в новомобъектный файл для связи на более позднем этапе.

1 голос
/ 05 апреля 2011

Если function() никогда не вызывается, возможно, он не включен в исполняемый файл, и вызванная из него функция также не ищется.

0 голосов
/ 22 июля 2014

«Стандартный» алгоритм, в соответствии с которым работают линкеры POSIX, оставляет возможность того, что код будет компилироваться и связываться без каких-либо ошибок. Подробности смотрите здесь: https://stackoverflow.com/a/11894098/187690

Чтобы использовать эту возможность, объектный файл, содержащий ваш function (назовем его f.o), должен быть помещен в библиотеку. Эта библиотека должна быть упомянута в командной строке компилятора (и / или компоновщика), но к этому моменту ни один другой объектный файл (упомянутый ранее в командной строке) не должен был делать какие-либо вызовы function или любой другой функции, присутствующей в f.o. При таких обстоятельствах компоновщик не видит причин для извлечения f.o из библиотеки. Линкер полностью игнорирует f.o, полностью игнорирует function и, следовательно, полностью игнорирует вызов made_up_function_name. Код скомпилируется, хотя made_up_function_name нигде не определен.

...