【C语言-函数-函数声明】对被调用函数的声明和函数原型——给编译器提前“打个招呼”

开发技术 作者: 精灵星空 SKY315.COM 更新于: 浏览: 237
码字发文不易,转载请注明出处【精灵星空 SKY315.COM】

上节课咱们学了调用函数,大家发现一个有意思的事没有?就是printf和scanf这些函数,我们在main函数里直接就调用了,编译器也没报错。

但是你定义一个自己的函数,如果在main后面实现,编译器就报错说不认识。

凭啥?这不公平啊!

原因特简单:编译器是个死脑筋,它从上往下看代码,看到的才认,没看到的就说不认识。

你想想,编译器读到main里面调用add的时候,它还没看到后面add长啥样呢,它心里想的是“这add是个啥玩意儿?没见过,报错!”

而printf为啥能直接用?因为你写了#include <stdio.h>,这个头文件里面提前告诉编译器了——“printf这个函数长这样,你先认着,具体的实现别处找去”。

所以今天咱们就讲一件事:怎么让你的函数也能像printf一样,在定义之前就能被调用。

这就是函数声明,也叫函数原型。

语法特别简单:把函数定义的第一行复制下来,后面加个分号,就行了。

比如你定义了一个函数:

int add(int a, int b) {
    return a + b;
}

那它的声明就是:

int add(int a, int b);

你看,一模一样,就是把后面的大括号和函数体换成个分号,完事。

这叫函数原型——它就像这个函数的“身份证”,告诉编译器:这个函数叫啥名,接收啥参数,返回啥类型。具体怎么做的不重要,重要的是让编译器知道“有这个函数存在”。

有了这个声明,你就能把函数定义写在调用处的后面了:

#include <stdio.h>

int add(int a, int b);   // 声明:先告诉编译器有这号人

int main() {
    int z = add(3, 5);   // 这时候编译器认识add了
    printf("%d\n", z);
    return 0;
}

int add(int a, int b) {  // 定义:具体实现放后面
    return a + b;
}

你看,编译器读到main里调用add的时候,往前翻了翻,看到了声明“哦,add是这个样子的,行,我知道了”,就不会报错了。后面再看到真正的定义的时候,它心里有数了。

有人可能要问了:那我在前面就直接把定义写了,不就不用声明了吗?

没错,确实不用。很多小项目就是这么干的——把函数定义都写在main前面,省事儿。

但是在实际开发中,你基本不可能把所有函数都堆在main前面。为啥?

第一,代码一多,你就得把函数分组放在不同文件里。比如一个文件专门放数学计算函数,一个文件专门放输入输出函数,一个文件是主程序。这时候你的main要用别的文件里的函数,就得靠头文件里的声明来“打招呼”。

第二,如果两个函数互相调用,比如A调用B,B又调用A。那你把谁放前面都不对——放A前面,编译器不认识B;放B前面,编译器不认识A。唯一的解决办法就是:把两个函数的声明都写在最前面,定义随便放哪儿都行。

函数声明其实可以写得比定义更“随性”一些。你看:

定义的时候,形参名是必须写的,因为你后面函数体里要用。

声明的时候,形参名可以省略,只写类型就够了。

int add(int, int);   // 合法,参数名可以省略

这两种写法都行。不过个人建议写上名字,因为看得更清楚——别人一看就知道“哦,第一个是a,第二个是b”,心里有谱。

还有一个很重要的概念:声明和定义是两码事。

  • 声明:告诉编译器“有这个函数存在,长这个样子”。不分配内存,不生成代码,就是个“口头告知”。

  • 定义:真正把函数体写出来,分配内存,生成机器码,函数实实在在地存在了。

你可以声明无数次,但只能定义一次。

打个比方:声明就像是你在学校公告栏贴个通知——“下周学校要办运动会”。你可以在校门口贴一张,食堂贴一张,教学楼贴一张,贴一百张都没问题,大家知道有这个事儿了。但是运动会真正办起来,只能办一次,不可能校门口办一场、食堂再办一场。

再说说#include和函数声明的关系。

实际上,你每次写#include <stdio.h>,就是把stdio.h这个头文件里的内容全部“复制粘贴”到你的代码里。而这个头文件里面有什么?有大量函数的声明。printf、scanf、strlen这些函数的声明全在里面。

所以你看,你早就用过函数声明了,只是以前不知道这回事而已。

#include <stdio.h>   // 这里面就装着一大堆函数声明

int main() {
    printf("Hello");  // 因为stdio.h里已经声明了printf,编译器认识它
    return 0;
}

等你学了多文件编程,你也会自己写头文件(.h文件),把一些函数声明放进去,然后让别人#include你的头文件,就能用你的函数了。

最后,给同学们总结一下这块的核心要点:

什么时候需要函数声明? 当你要调用的函数定义在调用处后面的时候,就需要在前面先声明一下。

函数原型怎么写? 把函数的第一行(返回值类型、函数名、参数列表)抄下来,后面加个分号就行。

声明和定义有啥区别? 声明是“告诉编译器有这个函数”,定义是“真正把这个函数写出来”。声明可以有多次,定义只能有一次。

声明里的参数名可以省略不写。

好了,同学们可以自己试试了。写一个函数,定义在main后面,然后在前面加个声明,看能不能编译通过。再把声明删了,看看编译器报什么错。亲手试一次,比背十遍都管用。