内部函数和外部函数
函数一旦定义后就可被其它函数调用。 但当一个源程序由多个源文件组成时,在一个源文件中定义的函数能否被其它源文件中的函数调用呢?为此,C语言又把函数分为两类:
一、内部函数
如果在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其它文件中的函数调用,这种函数称为内部函数。定义内部函数的一般形式是:
static 类型说明符 函数名(形参表)
内部函数也称为静态函数。但此处静态static的含义已不是指存储方式,而是指对函数的调用范围只局限于本文件。因此在不同的源文件中定义同名的静态函数不会引起混淆,但通过#include可以使用。
在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条。
(1)先来介绍它的第一条也是最重要的一条:隐藏。如果加了static,就会对其它源文件隐藏。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏,而对于变量,static还有下面两个作用。
(2)static的第二个作用是保持变量内容的持久。存储在静态数据区的变量(无论是函数内or函数外部)会在程序刚开始运行时就完成初始化,也是唯一的一次初始化,函数内部的数据不会在函数结束时就消失,而是一直到程序结束。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。
(3)static的第三个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。
二、外部函数
外部函数在整个源程序中都有效,其定义的一般形式为:
extern 类型说明符 函数名(形参表)
如在函数定义中没有说明extern或static则隐含为extern。在一个源文件的函数中调用其它源文件中定义的外部函数时,应用extern说明被调函数为外部函数。函数的声明extern关键词是可有可无的,因为函数本身不加修饰的话就是extern的。而全局变量在外部使用声明时,extern关键词是必须的,如果变量无extern修饰且没有显式的初始化,则成为变量的定义,因此此时必须加extern,而编译器在此标记存储空间在执行时加载如内存并初始化为0。而局部变量的声明不能有extern的修饰,且局部变量在运行时才在堆栈部分分配内存。
在声明的时候,extern居然可以被省略,所以会让你搞不清楚到底是声明还是定义,下面分变量和函数两类来说:
(1)变量
尤其是对于变量来说。
extern int a;//声明一个全局变量a
int a; //定义一个全局变量a
extern int a =0 ;//定义一个全局变量a 并给初值。
int a =0;//定义一个全局变量a,并给初值,
第四个 等于 第三个,都是定义一个可以被外部使用的全局变量,并给初值。
不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。当你要引用一个全局变量的时候,你就要声明,extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。
(2)函数
对于函数也一样,也是定义和声明,定义的时候用extern,说明这个函数是可以被外部引用的,声明的时候用extern说明这是一个声明。 但由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体,所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。两者如此不同,所以省略了extern也不会有问题。但是:虽然知道某个函数的声明,就可以调用这个函数,编译就能成功。不过想要这个程序能够运行成功,必须保证在链接的时候能找到函数的定义。
#include<stdio.h>
void fun();
int main()
{
fun();
}//即使没有定义fun(),编译也可以通过
通常全局变量的声明extern type data;和函数的声明会放在头文件.h里,然后使用时结合include功能。
总结下,对变量而言,如果你想在本源文件中使用另一个源文件的变量,就需要在使用前用extern声明该变量,或者在头文件中用extern声明该变量;
对函数而言,如果你想在本源文件中使用另一个源文件的函数,就需要在使用前用声明该变量,声明函数加不加extern都没关系,所以在头文件中函数可以不用加extern。
声明(Declaration)用于说明每个标识符的含义,而并不需要为每个标识符预存储空间。预留存储空间的声明称为定义(Definition)。变量的声明有两种情况: 一种是需要建立存储空间的。
例如:int a; 在声明的时候就已经建立了存储空间。
另一种是不需要建立存储空间。
例如:extern int a; 其中 变量a是在别的文件中定义的。
谨记:声明可以多次,定义只能一次。
在C里面,所谓 static ,只是限制在当前源文件————这个只是对于编译器/链接器而言。但实际上,运行时,static和普通的extern 的函数/变量,没有区别。
例如:使用函数指针/变量指针,完全可以访问其他文件的 static 变量/函数
file01.h
int * iptr01;
typedef void (* funcPtr)(void);
funcPtr pfun01;
----------------------------
file01.c
#include "file01.h"
static int ivar01 = 36;
int * iptr01 = &ivar01;
static void hwfun (void);
funcPtr pfun01 = &hwfun;
void hwfun (void)
{
printf("hello world\n");
}
-------------------------
file02.c
#include "file01.h"
............
//在某个代码内
*iptr01 = 72;
//file01.c 中的ivar01 变为72;
pfun01();
//调用了file01.c 中的hwfun ,打印出hello world