Вопрос по undefined-symbol, linker-errors, undefined-reference, c – Ошибка неопределенных символов при использовании файла заголовка

6

Я получаю следующую ошибку и не могу понять, что я делаю неправильно.

$ gcc main.c -o main

Undefined symbols:
  "_wtf", referenced from:
      _main in ccu2Qr2V.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

main.c:

#include <stdio.h>
#include "wtf.h"

main(){
    wtf();
}

wtf.h:

void wtf();

wtf.c:

void wtf(){
    printf("I never see the light of day.");
}

Теперь, если я включу в заголовочный файл всю функцию, а не только сигнатуру, она будет соответствовать, так что я знаю, что файл wtf.h включен. Почему компилятор не видит wtf.c? Или я что-то упустил?

С уважением.

Вы никогда не говорили компилятору компилировать wtf.c. Вот почему. Michael Foukarakis
Да, я из страны магии и единорогов, поэтому я просто предположил, что имя реализации, совпадающее с заголовком, позволило бы компилятору найти оба. Chris Cummings

Ваш Ответ

2   ответа
11

Вам нужно ссылкуwtf с вашимmain, Самый простой способ собрать его вместе -gcc свяжу их для вас, вот так:

gcc main.c wtf.c -o main

Более длинный путь (отдельная подборкаwtf):

gcc -c wtf.c
gcc main.c wtf.o -o main

Еще дольше (отдельная компиляция и компоновка)

gcc -c wtf.c
gcc -c main.c
gcc main.o wtf.o -o main

Вместо последнегоgcc позвони, ты можешь бежатьld прямо с тем же эффектом.

@ j33r: в момент, когда в вашей программе более одного.c файл, пришло время написать простойMakefile построить это. caf
Так что же мешает мне сделать следующее? #include <stdio.h> #include "wtf.h" #include "wtf.c" Это неприятно, но и идея включать аргумент для каждой реализации при запуске gcc. Chris Cummings
@ j33r: предположительно, ничто не мешаетвы. МыТем, кто нам нужен, чтобы зарабатывать деньги на написании C ++-кода для заработка, нужно, чтобы наши коллеги помешали нам сделать это, чтобы защитить их здравомыслие. (И если вы действительно не знали: одна из ключевых особенностей Cотдельная подборка, Среди прочего это позволяет нам иметь дело с безумными временами компиляции, с которыми идет включение файла препроцессора. Кроме того, есть также сокрытие информации, инкапсуляция и другие приятные - и, к сожалению, часто недооцениваемые - принципы.) sbi
4

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

Они могут находиться в C-файле рядом с файлом, выполняющим включение, они могут быть из предварительно скомпилированной статической библиотеки ссылок или из динамической библиотеки, загружаемой системным компоновщиком при чтении вашего исполняемого файла, или они могут поступать во время выполнения пользователем управляемая программистом явная динамическая загрузка (<a href="http://www.opengroup.org/onlinepubs/009695399/functions/dlopen.html" rel="nofollow noreferrer">dlopen()</a> семейство функций в Linux, например).

C не похож на Java, не существует неявного правила, что просто потому, что файл C включает в себя определенный заголовок, компилятор должен также сделать что-то, чтобы «волшебным образом» найти реализацию вещей, объявленных в заголовке. Вы должны сказать это.

Ты совершенно прав. Я предполагал, что пока заголовочный файл и реализация были названы одинаково, компилятор найдет оба, когда я включу заголовок. Chris Cummings
Это объяснениепочему отдельная компиляция является особенностью довольно полезно. Благодарю. gwg

Похожие вопросы