这段时间,在看中心后台服务软件源码时发现,有很多自定义函数未经申明却能在主程序中被调用,主程序中没有包括上述函数的头文件,我在各个目录中也找不到上述函数的头文件。这就奇怪了,连使用标准库函数printf()都要包括标准输入输出头文件<stdio.h>,何况是自定义函数?这个问题困扰了我很久。前天问中创公司奚钟华,他说:确实没有头文件,它也试过,在原来的目录中编写了一些新的函数,照葫芦画瓢地在Makefile中添加了相应项,生成了库文件,在主程序中就可调用了,其中的机理它也说不清。 今天通过实验,基本明白了个中原因。 一、在VC6中,文件test1.cpp如下:
#include "stdafx.h" // stdafx.h: #include <stdio.h>
int Max(int x, int y) { return ((x > y ) ? x : y); }
int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
程序正常运行,因为Max()在被调用前已经定义。
将Max()移到main()之后: #include "stdafx.h" // stdafx.h: #include <stdio.h>
int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
int Max(int x, int y) { return ((x > y ) ? x : y); }
编译时出错: error C2065: 'Max' : undeclared identifier error C2373: 'Max' : redefinition; different type modifiers
在main()之前添加Max()的声明: #include "stdafx.h" // stdafx.h: #include <stdio.h>
int Max(int x, int y);
int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
int Max(int x, int y) { return ((x > y ) ? x : y); }
程序正常运行,因为Max()在被调用前已经定义。
二、在Linux中,文件test2.c如下: #include <stdio.h>
int Max(int x, int y) { return ((x > y ) ? x : y); }
int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
用gcc编译:gcc -Wall -o test2 test2.c,通过。程序正常运行,因为Max()在被调用前已经定义。
将Max()移到main()之后: #include <stdio.h>
int main(int argc, char* argv[]) { int a = 300, b = 100; printf("Max(a, b): %d/n", Max(a, b)); return 0; }
int Max(int x, int y) { return ((x > y ) ? x : y); }
用gcc编译:gcc -Wall -o test2 test2.c,出现警告: warning: implicit declaration of function `Max' 仍然编译通过,程序也能正常运行,因为在C语言中,当函数在调用函数之前没有声明或定义,默认作为隐式声明处理,只要在调用函数之后定义,或在别的模块中定义并编译成库文件,该库文件在调用函数所属模块编译时载入,程序即可正常运行。
用g++编译:g++ -Wall -o test2 test2.c,出现错误和警告: error: `Max' was not declared in this scope warning: unused variable 'Max' 没有生成可执行程序test2。因为g++使用C++的规则:函数在被调用前必须声明或定义。
三、在Linux中,采用实际工程的方式(分成若干模块)进一步实验,验证了C语言中函数在被调用前不申明也能使用。 1、在/u01/work/tools目录中,编写4个文件: Max.c: int Max(int x, int y) { return ((x > y ) ? x : y); }
Min.c: int Min(int x, int y) { return ((x > y ) ? y : x); }
Add.c: int Add(int x, int y) { return (x + y); }
Makefile: #User defined library, by He Yaozhong CC=gcc HOME=/u01/work OS=$(HOME)/tools
INCLUDE=$(HOME)/headfile -I$(HOME)/tools
CSTARGETS=Max.o Min.o Add.o
LIBS=$(HOME)/lib/tools.a
all: $(LIBS) clean
Max.o : Max.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Max.c
Min.o : Min.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Min.c
Add.o : Add.c $(CC) -I$(INCLUDE) -c $(CCFLAGS) Add.c
$(LIBS) : $(CSTARGETS) cd $(OS); / ar ruv $(LIBS) $(CSTARGETS:$HOME/lib/=)
clean: rm -f *.o
在/u01/work/tools目录中,使用make工具: [root@node01 tools]# make gcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Max.c gcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Min.c gcc -I/u01/work/headfile -I/u01/work/tools -Wall -c Add.c cd /u01/work/tools; / ar ruv /u01/work/lib/tools.a Max.o Min.o Add.o r - Max.o r - Min.o r - Add.o rm -f *.o 生成了/u01/work/lib/tools.a库文件。
2、在/u01/work/test2目录中,编写2个文件: test2.c: #include <stdio.h>
int main(int argc, char* argv[]) { int a, b;
printf("Please input 2 integer (a, b): /n"); scanf("%d", &a); scanf("%d", &b);
printf("Max(a, b): %d/n", Max(a, b)); printf("Min(a, b): %d/n", Min(a, b)); printf("Add(a, b): %d/n", Add(a, b));
return 0; }
Makefile: CC=gcc HOME=/u01/work
INCLUDE=-I$(HOME)/headfile -I.
CFLAGS= -L$(HOME)/lib
LIBS=$(HOME)/lib/tools.a
all : $(OBJS) test2 clean
test2 : test2.c $(CC) $(INCLUDE) -Wall -o test2 test2.c $(CFLAGS) $(LIBS)
clean : rm -f *.o
在/u01/work/test2目录中,使用make工具: [root@node01 func_pointer]# make gcc -I/u01/work/headfile -I. -Wall -o test2 test2.c -L/u01/work/lib /u01/work/lib/tools.a test2.c: In function `main': test2.c:11: warning: implicit declaration of function `Max' test2.c:12: warning: implicit declaration of function `Min' test2.c:13: warning: implicit declaration of function `Add' rm -f *.o 生成了/u01/work/test2/test2可执行文件。运行程序: [root@node01 func_pointer]# ./test2 Please input 2 integer (a, b): 200 300 Max(a, b): 300 Min(a, b): 200 Add(a, b): 500
结果完全正确。
四、小结 C和C++是强类型语言,变量类型均应在代码执行前确定。 在函数声明方面C和C++则不同,C++语言中,在被调用之前未声明或定义是不允许的,而C语言是允许的。初看起来C语言这一特性是灵活、省事,但缺点是: 1、程序可读性差。 2、易出错。函数先声明再调用,是一种纠错机制,如果不声明,则没有用到这种纠错机制,虽然编译、连接通过,程序也能运行,但很可能结果不正确。
一个好的程序员,应该养成严谨、规范的编程习惯,编译程序时应打开显示所有警告选项“-Wall”,并且对编译器提出的所有警告都要给予处理,仅以编译、连接通过为目标,这可能会有潜在的危害。 |
|
来自: 败败0619 > 《Linux/Ubuntu》