C中使用extern修饰函数

来源:互联网 发布:软件售后服务收费标准 编辑:程序博客网 时间:2024/05/20 14:19

用extern修饰函数是表示被修饰的函数定义在当前文件外,而该函数用extern声明类型后就可以被当前文件调用了。使用extern修饰某函数时,对该函数的调用是在连接阶段才被处理的。下面我们看一段代码。

/***********************************************
 * fun.c
 ***********************************************/

#include <stdio.h>

void fun (int n)
{
 printf("%d/n");
}


/***********************************************
 * test.c
 ***********************************************/

extern void fun (void);

int main ()
{
 fun();
 return 0;
}

着两个文件能编译连接到一起吗?答案是肯定的,而且不会出现警告。那我们运行这个程序看看什么结果:

C:/> test.exe
2367460

出现这种情况的原因:

C中不支持多态,因此就没有函数重载。使用extern修饰函数时,该函数在调用时才被连接。由于C不支持多态,按照C的编译方式,两个函数虽然有不同的参数,但是C却会把他们编译成同样的名字,因此虽然是两个不同的函数,调用时也不传递参数,但是由于是调用时才被连接的,调用时只检查函数的名字,因此却能调用到fun(int n)这个函数。

注意一点:C中使用extern修饰函数时,函数在被调用时才被连接。因此要注意两个函数的声明是否是一致的。


这个数从哪来的?不知道。这是因为我们调用了一个需要参数的函数而没有传递参数给它,而这个函数还傻乎乎的以为传过了参数,从寄存器里读出它的参数就去干活了。那个寄存器里是什么值?谁也说不准。如果fun函数的参数是作为指针使用……,啊!麻烦大了!

要解决问题,对于上面的小程序,我们直接冲过去改掉就成了。但是如果你的程序里有1000个文件,平均每个文件5000行(真正大的项目要比这大的多),那你还能一行行检查下去吗?如果调试过程中出了问题而你还不知道是这个原因导致的,如果你的程序很少运行到这个地方,……

所以,正确的方法是防患于未然,写代码是养成良好的习惯。

对于使用gcc的朋友,建议总是使用“-Wall”,“-Wall”是一个细心的秘书,他会及时提醒你代码中存在的风险。

尽量避免使用extern修饰函数。一般情况下,如果我们希望某个函数可以被外界使用,就创建一个头文件,在其中声明该函数的类型。哪个程序需要调用这个函数就把它的头文件包含进去。这样一来如果调用的地方使用不当,在编译阶段就会提示错误,也节省了时间。而且,定义函数和声明函数是同一个人做的,出错的机会也就小了。

 

 

变量
在将变量前,先解释一下声明和定义这两个概念。声明一个变量意味着向编译器描述变量的类型,但并不为变量分配存储空间。定义一个变量意味着在声明变量的同时还要为变量分配存储空间。在定义一个变量的同时还可以对变量进行初始化。
局部变量通常只定义不声明,而全局变量多在源文件中定义,在头文件中声明。
局部变量
在一个函数的内部定义的变量是内部变量,它只在本函数范围内有效。
自动变量auto
函数中的局部变量,其缺省格式是自动变量类型。例如,在函数体中int b, c=3; 和auto int b, c=3; 是等价的。
自动变量是动态分配存储空间的,函数结束后就释放。自动变量如不赋初值,则它的值是一个不确定的值。
静态局部变量static
静态局部变量是指在函数体内声明和定义的局部变量,它仅供本函数使用,即其他函数不能调用它。静态局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释放,在下一次函数调用时,该变量已有值,就是上一次函数调用结束时的值。
静态局部变量在静态存储区分配存储单元,在程序的整个运行期间都不释放。静态局部变量是在编译时赋初值的,即只赋初值一次。
在SDT编译器中,建议对静态局部变量赋初值,否则该静态局部变量的初值为不确定值。在其他编译器中,未初始化的静态局部变量的初值可能为零,这由具体的编译器所决定,使用前最好测试一下。
寄存器变量register
带register修饰符的变量暗示(仅仅是暗示而不是命令)编译程序本变量将被频繁使用,如果可能的话,应将其保留在CPU的寄存器中,以加快其存取速度。
对于现有的大多数编译程序,最好不要使用register修饰符。因为它是对早期低效的C编译程序的一个很有价值的补充。随着编译程序技术的进步,在决定哪些变量应当被存到寄存器中时,现在的C编译程序能比程序员做出更好的决定。
全局变量
在函数之外定义的变量称为外部变量,外部变量是全局变量,它可以为本文件中其他函数所共用。全局变量都是静态存储方式,都是在编译时分配内存,但是作用范围有所不同。
静态外部变量static
静态外部变量只能在本文件中使用。所以静态外部变量应该在当前源文件中声明和定义。
外部变量extern
定义函数中的全局变量时,其缺省格式是外部变量类型。外部变量应该在一个头文件中声明,在当前源文件中定义。外部变量允许其他文件引用。
下例声明了一个变量和一个结构,定义了两个变量,其中一个定义带初始化:
extern int   decl1;   // this is a declaration

struct decl2
{
  int member;
};       // this just declares the type – no variable mentioned

int     def1 = 8;   // this is a definition

int     def2;   // this is a definition
函数
内部函数的声明和定义多在当前源文件中完成;而外部函数通常在源文件中定义,在头文件中声明。
内部函数
只在当前源文件中使用的函数应该说明为内部函数。内部函数应该在当前源文件中声明和定义。若内部函数在头文件中声明,其他源文件通过包含这个头文件也可使用这个函数,但这样就失去了其做为内部函数的意义。
优点:使用内部函数,可以使函数只局限于所在文件。这避免了与其他源文件中可能出现的同名函数发生冲突。
例:
File: function1.c
#include “function1.h”
static int stat_func(void);

void MasterFunction(void)
{

rc = stat_func( );

}

static int stat_func(void)
{
  …
  return rc;
}

外部函数
对于可在当前源文件以外使用的函数,应该在一个头文件中声明。其他源文件可通过包含这个头文件或进行声明来使用这些函数(推荐用前者)。
一个良好的编程习惯是在头文件中声明函数的原型。这可方便编译程序查错。定义函数时,缺省的函数类型是外部函数。如:void fun2(void); 和extern void fun2(void); 其函数类型是等价的,但前一个是定义函数,后一个是声明函数。
小结
编写程序,尤其是大型程序时,建议采用上文所述的方法对不同的变量、函数进行必要的声明、定义。做好这些细节上的事务,可以为您的编程、调试、移植等带来很大的方便。

0 0
原创粉丝点击