2

我写了一个关于结构的示例程序。我写了 3 个源文件和 1 个头文件。这是程序的完整源代码:

主.c:

#include <stdio.h>
#include <stdlib.h>
#include "fish.h"

/*
struct fish
{
    const char *name;
    const char *species;
    int teeth;
    int age;
};
*/

/*
void catalog(struct fish f)
{
    printf("%s is a %s with %i teeth. He is %i.",
           f.name, f.species, f.teeth, f.age);
}


void label(struct fish f)
{
    printf("Name: %s\n", f.name);
    printf("Species: %s\n", f.species);
    printf("Teeth: %i\n", f.teeth);
    printf("Age: %i\n", f.age);
}
*/

int main()
{
    struct fish snappy = {"Snappy", "Piranha", 69, 4};
    catalog(snappy);
    label(snappy);

    return 0;
}

标签.c:

#include "fish.h"

void label(struct fish f)
{
    printf("Name: %s\n", f.name);
    printf("Species: %s\n", f.species);
    printf("Teeth: %i\n", f.teeth);
    printf("Age: %i\n", f.age);
}

目录.c:

#include "fish.h"

void catalog(struct fish f)
{
    printf("%s is a %s with %i teeth. He is %i.",
           f.name, f.species, f.teeth, f.age);
}

我还写了一个makefile:

fish.o: main.c label.c catalog.c fish.h
    gcc -c main.c label.c catalog.c
fish: fish.o
    gcc fish.o -o fish

我在cmd中编译程序:

make fish

它说:

gcc -c main.c label.c catalog.c
label.c: In function 'label':
label.c:5:5: warning: incompatible implicit declaration of built-in function 'printf'    [enabled by default]
catalog.c: In function 'catalog':
catalog.c:5:5: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
cc   fish.o   -o fish
cc.exe: error: fish.o: No such file or directory
cc.exe: fatal error: no input files
compilation terminated.
make: *** [fish] Error 1

如果我删除 main.c 中的注释并只编译它,它可以工作,但是当我像上面提到的那样分成小块时它不起作用。

怎么了?

4

3 回答 3

4

您需要将所有.c文件一起编译,以便可以在main.c中使用label.ccatalog.c中定义的函数。

您可以使用 gcc 一步完成:

gcc main.c label.c catalog.c -o fish

这将编译每个单独的源文件并生成目标文件,这些文件将链接在一起以生成您的可执行文件。您看到的错误发生在链接阶段,当 gcc 试图找到catalogandlabel函数时。

于 2012-08-22T04:58:36.263 回答
3

gcc main.c -o fish只编译main.c. main.c不知道label.c。它只知道它必须调用一些名为“label”的函数,该函数在别处定义。然后,链接器查看所有生成的目标文件,并将它们“链接”到单个可执行文件中:

gcc main.c -c
gcc label.c -c
gcc catalog.c -c
ld main.o label.o catalog.o -o fish

这是显式版本

gcc main.c label.c catalog.c -o fish
于 2012-08-22T05:04:47.757 回答
2

此链接规则:

fish: fish.o
    gcc fish.o -o fish

适用于fish从单个目标文件fish.o(可能是从 编译的fish.c)构建程序。

你需要一个不同的规则:

OBJECTS = main.o label.o catalog.o

fish: ${OBJECTS}
    ${CC} -o $@ ${OBJECTS}

如果需要,您可以在链接行中适当添加${CFLAGS}and${LDFLAGS}${LDLIBS}(或${LDLIBES}),但对于简单的程序,我展示的内容就足够了。

您不必告诉make如何转换main.cmain.o; 它已经知道了。它将使用如下规则:

%.o: %.c
    ${CC} -c ${CFLAGS} $<

.o从匹配文件创建.c文件。(这是 GNU Make 表示法;POSIXmake和其他经典版本make使用另一种但松散等效的表示法.c.o:代替%.o: %.c.)

如果您不介意每次都编译所有源代码,则可以使用类似的规则:

SOURCES = main.c label.c catalog.c

fish: ${OBJECTS}
    ${CC} ${CFLAGS} -o $@ ${SOURCES}

这一次,${CFLAGS}实际上是强制性的(尽管在你的基本示例程序中没有它你就可以逃脱)。


请注意,这make很挑剔;命令行等命令行${CC}必须以TAB;开头 空格不行。

于 2012-08-22T05:31:10.333 回答