您需要将1_square.c 文件添加到您的构建命令中:
gcc -o 0_main 0_main.c 1_square.c && ./0_main
您需要函数的定义及其声明。
来自cmets:
为什么它需要在命令行中使用1_square.c,然后在0_main.c 标头中也需要1_square.h?
就像 John Bollinger 在 cmets 中指出的那样,1_square.h 和 1_square.c 的唯一共同点是它们的名称,这对编译器没有意义。就 gcc 而言,它们之间没有内在的关系。
让我们首先将所有内容放在一个源文件中:
/** main.c */
#include <stdio.h>
int square( int num );
int main( int argc, char **argv )
{
int a = 4;
int a_squared = square( a );
printf( "Square of %d is %d\n", a, a_squared );
return 0;
}
int square( int num )
{
return num * num;
}
在 C 中,函数必须在源代码中调用之前声明;声明介绍了函数名称、它的返回类型以及它的参数的数量和类型。这将让编译器在翻译过程中验证函数调用是否正确编写,如果不是,则发出诊断,而不是等到运行时抛出错误。在这种特殊情况下,我们指定 square 函数采用单个 int 参数并返回 int 值。
这并没有说明 square 函数本身或其运作方式 - 这是由 square 函数的定义稍后提供的。
函数定义也用作声明;如果调用者和被调用函数都在同一个翻译单元(源文件)中,那么您可以将定义放在调用之前,而根本不必弄乱单独的声明:
/** main.c */
#include <stdio.h>
int square( int num )
{
return num * num;
}
int main( int argc, char **argv )
{
int a = 4;
int a_squared = square( a );
printf( "Square of %d is %d\n", a, a_squared );
return 0;
}
这实际上更可取,因为您不必在两个不同的地方更新函数签名。这意味着您的代码“向后”读取,但老实说,这是一种更好的方法。
但是,如果您将函数分离到一个单独的源文件中,那么您需要有一个单独的声明:
/** main.c */
#include <stdio.h>
int square( int num );
int main( int argc, char **argv )
{
int a = 4;
int a_squared = square( a );
printf( "Square of %d is %d\n", a, a_squared );
return 0;
}
/** square.c */
int square( int num )
{
return num * num;
}
在处理main.c 时,编译器不知道square.c 中square 函数的定义 - 它甚至不知道文件存在 。 main.c 是否在 square.c 之前编译无关紧要,反之亦然;编译器一次对一个文件进行操作。关于square 函数,编译器唯一知道的是main.c 中的声明。
必须为单独的 .c 文件中定义的每个函数手动添加声明是一件很痛苦的事情 - 您不想为 printf、scanf、fopen 等编写单独的声明. 所以按惯例我们创建一个单独的.h 文件,与.c 文件同名来存储声明:
/** main.c */
#include <stdio.h>
#include "square.h"
int main( int argc, char **argv )
{
int a = 4;
int a_squared = square( a );
printf( "Square of %d is %d\n", a, a_squared );
return 0;
}
/** square.h */
int square( int num );
/** square.c */
int square( int num )
{
return num * num;
}
按照惯例,我们还在 .h 文件中添加 include 保护 - 这样可以防止每个翻译单元多次处理文件的内容,如果您 #include "square.h" 可能会发生这种情况并包含另一个标题,也包含square.h。
/** square.h */
#ifndef SQUARE_H // the contents of this file will only be
#define SQUARE_H // processed if this symbol hasn't been defined
int square( int num );
#endif
同样按照惯例,我们将.h 文件包含在.c 文件中,以确保我们的声明与我们的定义一致——如果不符合,编译器会报错:
/** square.c */
#include "square.h"
int square( int num )
{
return num*num;
}
main.c 和square.c 都被编译后,它们的目标代码将被链接到一个可执行文件中:
main.c ------+-----> compiler ---> main.o ----+--> linker ---> main
| |
square.h ----+ |
| |
square.c ----+-----> compiler ---> square.o --+
我们必须编译两个 C 文件并将它们的目标代码链接在一起,以获得一个工作程序。毫无疑问,您的 IDE 让这一切变得简单——您只需将源文件添加到项目中,它就会正确构建它们。 gcc 可让您在一个命令中完成所有操作,但您必须列出项目中的所有 .c 文件。
如果您从命令行运行,您可以使用make 实用程序来简化操作。您需要创建一个如下所示的 Makefile:
CC=gcc
CFLAGS=-std=c11 -pedantic -Wall -Werror
main: main.o square.o
all: main
clean:
rm -rf main *.o
您需要做的就是在命令行输入make,它会使用内置规则编译main.c 和square.c 来构建您的项目。