有人问:C语言为什么只需要include<stdio.h>就能使用里面声明的函数?这是一个看起来非常简单的问题,但是很多初学者,甚至学了很久的人都可能没有搞明白。为什么包含即可用?
要明白包含即可用的原因,就必须讲到C语言代码是如何变成可执行文件的了,这里可以参考《hello程序是如何变成可执行文件的》。这里使用#include指令,在预编译之后,相当于把文件里面的内容都放到.c中了。//hello.c
#include<stdio.h>
int main(void)
{
printf("hello,编程珠玑\n");
return 0;
}
$ gcc -E -o hello.i hello.c
执行完成之后,就可以看到hello.i里面涵盖了stdio.h中所有的内容。所以实际上,你只是在你的.c中声明了这些函数,既然声明了,那么你就可以使用。但是你要想真正用到它,还需要找到它的定义。这是在链接阶段做的事情。链接的时候,链接器会知道,诶,你这个程序需要printf函数啊?好的,我去libc.so里面找找,看看有没有哈。,巧了,还真有,恭喜你可以用。所以,这是一个,你用了,然后编译器帮你找了,而且还找到了的巧合事件而已。包含就够吗?
这个事情表面上看起来理所当然。但是有一个非常重要的前提://pow.c
//来源:公众号【编程珠玑】
//作者:守望先生
#include<stdio.h>
#include<math.h>
int main(void)
{
double pow(double x, double y);
double a = 2;
double c = pow(a,4);
printf("%f ^ 4 = %f\n",a,c);
return 0;
}
$ gcc -o pow pow.c
/tmp/ccnou5WK.o: In function `main':
pow.c:(.text+0x2f): undefined reference to `pow'
collect2: error: ld returned 1 exit status
所以说,并不是包含了就可以用。在这种情况下,你必须告诉它,我要用pow函数,并且你要去math库找,于是,按照下面的方式进行编译链接:不包含可以用吗?
那么一定要包含才可以使用吗?并非如此。前面说过了,包含不过是使用里面的声明,既然如何,我们自己声明怎么样?看下面的代码://hello.c,没有包含stdio.h
int printf (const char *__restrict __format, ...);
//extern int printf (const char *__restrict __format, ...);
int main(void)
{
printf("hello,编程珠玑\n");
return 0 ;
}
同样可以好好运行,因为你可以自己声明或者指定为外部声明。不过这样不建议,因为一旦出现自己声明的与实际的不符合,就可能导致意料不到的事情发生。总结
stdio.h里面的函数,包含即可用,只是巧合而已。包含并调用,只是表明你要用,而能不能用,取决于你有没有。通常stdio.h中的函数,基本都在libc库中,因此都可以用。不包含,但是自己声明调用,同样可以用,当然并不推荐这样做。所以最终决定你能不能用,是要看自己有没有定义以及其他地方有没有定义。为便于理解,本文不涉及太多具体的编译链接知识,有兴趣的可以自行扩展。
关注公众号【编程珠玑】,获取更多Linux/C/C++/数据结构与算法/计算机基础/工具等原创技术文章。后台免费获取经典电子书和视频资源