《C陷阱与缺陷》第5章库函数有一个练习题:
#define EOF -1 main() { register int c;
while ((c = getchar()) != EOF) putchar(c); } 这个程序在许多系统中仍然能够运行,但是在某些系统运行起来却慢得多。这是为什么? |
我们把关注点放在该程序没有包含头文件而在许多系统仍然能够运行,而不去考虑为什么在某些系统运行起来却慢得多。
先跑一下,看该程序能否正常运行。
[root@]# cat program.c
#define EOF -1
int main()
{
register int c;
while ((c = getchar()) != EOF)
putchar(c);
}
[root@]# gcc -o program program.c
[root@]# ./program
hello,world
hello,world
hello,root
hello,root
[root@]#
经验证,该程序在CentOS 5.5下运行正常。
再来看另外一个程序。
[root@]# cat program.c
int main()
{
double ret;
ret = cos(30);
printf("ret = %.2f\n", ret);
}
[root@]# gcc -o program program.c
program.c: In function ‘main’:
program.c:6: 警告:隐式声明与内建函数 ‘cos’ 不兼容
program.c:7: 警告:隐式声明与内建函数 ‘printf’ 不兼容
/tmp/ccYZtVM3.o: In function `main':
program.c:(.text+0x1c): undefined reference to `cos'
collect2: ld 返回 1
[root@]# gcc -o program program.c -lm
program.c: In function ‘main’:
program.c:6: 警告:隐式声明与内建函数 ‘cos’ 不兼容
program.c:7: 警告:隐式声明与内建函数 ‘printf’ 不兼容
[root@]# ./program
ret = 0.15
[root@]#
编译命令为:gcc -o program program.c时,出现cos未定义的错误。当编译选项相对第一个示例多一个-lm时,编译成功。但有两处告警。
继续看第三个程序示例。
[root@]# cat program.c
void *thread_func(void *arg);
char message[] = "hello, thread";
int main()
{
int ret;
unsigned long a_thread;
void *thread_ret;
ret = pthread_create(&a_thread, 0, thread_func, (void *)message);
if (ret != 0)
{
perror("Thread creation failed");
exit(1);
}
printf("Waiting for thread to finish...\n");
ret = pthread_join(a_thread, &thread_ret);
if (ret != 0)
{
perror("Thread join failed");
exit(1);
}
printf("Thread join, it returned %s\n", (char *)thread_ret);
return 0;
}
void *thread_func(void *arg)
{
printf("thread_func is running. Argument was %s\n", (char *)arg);
pthread_exit("Thank you for the CPU time");
}
[root@]# gcc -o program program.c
program.c: In function ‘main’:
program.c:15: 警告:隐式声明与内建函数 ‘exit’ 不兼容
program.c:18: 警告:隐式声明与内建函数 ‘printf’ 不兼容
program.c:23: 警告:隐式声明与内建函数 ‘exit’ 不兼容
program.c: In function ‘thread_func’:
program.c:32: 警告:隐式声明与内建函数 ‘printf’ 不兼容
/tmp/ccAEXJyb.o: In function `main':
program.c:(.text+0x21): undefined reference to `pthread_create'
program.c:(.text+0x5f): undefined reference to `pthread_join'
collect2: ld 返回 1
[root@]# gcc -o program program.c -lpthread
program.c: In function ‘main’:
program.c:15: 警告:隐式声明与内建函数 ‘exit’ 不兼容
program.c:18: 警告:隐式声明与内建函数 ‘printf’ 不兼容
program.c:23: 警告:隐式声明与内建函数 ‘exit’ 不兼容
program.c: In function ‘thread_func’:
program.c:32: 警告:隐式声明与内建函数 ‘printf’ 不兼容
[root@]# ./program
Waiting for thread to finish...
thread_func is running. Argument was hello, thread
Thread join, it returned Thank you for the CPU time
[root@]#
结果发现,当编译命令为:gcc -o program program.c时,出现pthread_create()和pthread_join()未定义。当编译选项相对第一个示例多一个-lpthread时,编译成功,只是还有几处告警。
接下来,分析这三个程序。
第一个程序主要包含了库函数getchar()和putchar()。第二个程序主要包含了库函数cos()。第三个程序主要包含了pthread_create()和pthread_join()。
再来看下三个编译命令:
第一个程序:gcc -o program program.c
第二个程序:gcc -o program program.c -lm
第三个程序:gcc -o program program.c -lpthread
第二个和第三个编译命令相对第一个多了-lm和-lpthread选项。该选项的作用是告诉编译器去链接共享库libm.so和libpthread.so。而函数cos()就在共享库libm.so里定义,pthread_create()和pthread_join()就在共享库libpthread.so里定义。故而,在分别链接了这两个共享库之后,出现的那些未定义错误就消失了。
那第一个程序的getchar()和putchar()呢?该程序中并没有定义它们,但为何能正确执行呢?其实,我们知道getchar()和putchar()是标准库函数。而标准库函数的共享库名称是libc.so。gcc编译器在编译时,会自动链接该共享库,故而可以不用指定链接共享库的选项。
#include文件名 | 库路径名 | 所用的编译器选项 |
<math.h> | /usr/lib/libm.so | -lm |
<stdio.h> | /usr/lib/libc.so | 自动链接 |
<pthread.h> | /usr/lib/pthread.so | -lpthread |
头文件主要包含一些宏定义、类型定义及函数原型。包含函数原型的作用在于编译时及时发现错误,如参数的个数、类型匹配问题。