C: Заголовочный файл и включите вопрос.Нужна помощь! - PullRequest
2 голосов
/ 24 января 2011

Насколько я понимаю, C имеет make-файлы и включает в себя операторы, поэтому у вас нет файлов с единичным размером монстров, и вам следует функционально декомпозировать ваш код. Поэтому, если я прав, я должен иметь возможность выполнять функциональные вызовы для файлов .c, если я правильно делаю заголовки и выполняю их правильно.

Я пытаюсь это сделать, но, к сожалению, получаю ошибку.

Файлы имеют следующее содержимое:

Файл 1) test.c:

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

main()
{
    printf("Hello World\n\n");
    printf("This is the number: %d \n\n", suc(6));
}

Файл 2) makefile:

CC=gcc
CFLAGS=-c -Wall

test: suc.o
$(CC) -Wall -o test test.c

suc.o: suc.c
$(CC) $(CFLAGS) suc.c

Файл 3) suc.h

#ifndef SUC_H_GUARD

#define SUC_H_GUARD

// returns the successor of i (i+1)
int suc(int i);


#endif

Файл 4) suc.c

#include "suc.h"

int suc(int i)
{
return i + 1;
}

Когда я делаю (make -B) вершину, я получаю:

gcc -c -Wall suc.c
gcc -Wall -o test test.c
test.c:7: warning: return type defaults to 'int'
/tmp/cc/7w7qCJ.o: In function 'main':
test.c: (.text+0x1d): undefined reference to 'suc'
collect2: ld returned 1 exit status
make: *** [test] Error 1

Тем не менее: Оба дают ожидаемые результаты: A) Эта отдельная файловая программа работает нормально!

#include<stdio.h>

main()
{
    printf("Hello World\n\n");
printf("This is the number: %d \n\n", suc(6));
}

int suc(int i)
{
return i + 1;
}

B) Все файлы в оригинале, но со следующим изменением test.c:

#include<stdio.h>
#include"suc.h" //suc() is still defined b/c suc.h is included

main()
{
    printf("Hello World\n\n");
printf("This is the number: %d \n\n", 4); //HERE! -> no function call
}

Помогите, пожалуйста и спасибо! Я не совсем понимаю, о чем мне говорят сообщения об ошибках.

Ответы [ 8 ]

4 голосов
/ 24 января 2011

В вашем случае вы компилируете два файла "suc.c" и "test.c" в два разных объектных файла - "suc.o" и "test.o". Однако, когда вы связываете вашу программу, вы указываете только один объектный файл, что делает невозможным для компоновщика найти определение или функцию "suc". Вы должны исправить ваши файлы make следующим образом:

suc.o: suc.c
    $(CC) $(CFLAGS) suc.c

test.o: test.c
    $(CC) $(CFLAGS) test.c

test: suc.o test.o
    $(CC) -Wall -o test suc.o test.o

Удачи!

4 голосов
/ 24 января 2011

Вам необходимо отдельно скомпилировать исходные файлы в их объектные файлы, а затем связать объектный файл, чтобы получить исполняемый файл test.

Так что вам нужно:

CC=gcc
CFLAGS=-c -Wall

test: test.o suc.o
<tab>$(CC) -Wall -o test test.o suc.o

test.o: test.c
<tab>$(CC) $(CFLAGS) test.c

suc.o: suc.c
<tab>$(CC) $(CFLAGS) suc.c

, где <tab> - вкладка.


Проблема в вашем текущем make-файле находится здесь:

test: suc.o
    $(CC) -Wall -o test test.c

, в котором говорится, что test зависит от suc.o, и для получения test вам нужно сделать:

$(CC) -Wall -o test test.c

но посмотрите на эту строку компиляции / ссылки, она не включает в себя какой-либо исходный / объектный файл, для которого определена функция suc.

Вы можете добавить suc.o как:

$(CC) -Wall -o test test.c suc.o

Но это считается плохим, потому что, скажем, вы меняете только файл suc.c, тогда ваш make-файл будет регенерировать suc.o и также должен будет регенерировать test, но для регенерации test вы перекомпилируете test.c даже думал, что это не изменилось.

2 голосов
/ 24 января 2011

В дополнение ко всем ответам, указывающим на связь с «suc.o», предупреждение return type defaults to 'int' говорит о том, что вы забыли объявить тип возврата для вашей main() функции.Правильное определение выглядит примерно так:

int main(int argc, char *argv[])
2 голосов
/ 24 января 2011

Вы должны указать компоновщику включить скомпилированный код в suc.o (созданный на первом этапе компиляции), потому что компоновщик C довольно глуп; он не знает о реализации функции по волшебству. (Даже иногда полезно, что именно так!)

Выполнение второго шага компиляции с этим должно работать:

gcc -Wall -o test test.c suc.o
2 голосов
/ 24 января 2011

При создании теста вы не связываете suc.o in.

Скомпилируйте test.c и suc.c в объектные файлы, затем свяжите их оба в окончательный test исполняемый файл.

Этот make-файл должен работать (убедитесь, что вы заменяете пробелы символами табуляции в правилах):

CC=gcc
CFLAGS=-c -Wall

.PHONY: all
all: test

test: test.o suc.o
    $(CC) -Wall test.o suc.o -o test

test.o: test.c
    $(CC) $(CFLAGS) test.c

suc.o: suc.c
    $(CC) $(CFLAGS) suc.c
1 голос
/ 24 января 2011
gcc -c file.c 

скомпилирует file.c в объектный файл file.o.

gcc -o test test.c 

скомпилирует и свяжет test.c с исполняемым файлом.

Но чтобы создать исполняемый файл, вам нужно связать все необходимые объектные файлы, в вашем случае suc.o, поэтому вы должны написать либо

gcc -c test.c
gcc -c sic.c
gcc -o test test.o sic.o

либо

gcc -o test test.c sic.c
1 голос
/ 24 января 2011

Сбой этой строки зависимости:

test: suc.o
   $(CC) -Wall -o test test.c

потому что вы не связываетесь с suc.o (и, кстати, тест зависит от suc.o и test.o)

ваши строки должны быть:

test: test.o suc.o
   $(CC) -Wall -o test test.o suc.o

test.o : test.c
   $(CC) -c test.c
0 голосов
/ 24 января 2011

Здесь, конечно, уже достаточно ответов.Еще один не может повредить.Сделать это (в общем) довольно умно.Пусть он использует свои знания стандартных правил сборки и упростит ваш Makefile до одной строки:

test: test.o suc.o

Не пытайтесь дать ему простые правила сборки, потому что он обычно может их угадать.(Я думаю о gnu make, но большинство (если не все) версии будут делать то же самое.)

Также, в качестве примечания, подумайте о переименовании вашего исполняемого файла.Название «test» вызывает много путаницы, так как всякий раз, когда вы пытаетесь запустить его, вы неожиданно получаете либо встроенную оболочку, либо /bin/test.

.
...