注:本篇博客的内容和列子都来源于书籍《c和指针》,是lc整理成篇的,推荐大家读读这本书。
所谓抽象数据类型,是指模块具有功能说明和接口说明,前者说明模块所执行的任务,后者定义模块的使用。但是,模块的用户并不需要知道模块实现的任何细节,而且除了那些定义好的接口之外,用户不能以任何方式访问模块,这个定义觉得是不是和面向对象语言的类的定义类似呢,c没提供类这种结构,c实现抽象数据类型的武器其实是static关键字。
c语言有三种链接属性,即external(外部),internal(内部)和none(无)。没有链接属性的标识符(none)总是被当作单独的实体,也就是说该标识符的多个声明被当作独立不同的实体。属于Internal链接属性的标志符在同一个源文件内的所有声明中都指同一个实体,但位于不同源文件的多个声明则分属不同的实体,最后,属性external链接属性的标识符不论声明多少次,位于几个源文件都表示同一个实体。
关键字static和extern用于在声明中修改标识符的链接属性,如果某个声明在正常情况下具有external链接属性,在它前面加上static关键字可以使它的链接属性变为internal。
一般而言,函数参数,函数局部变量(没有extern属性修饰)的变量都具有none的链接属性;全局变量,函数声明,函数定义如果没有static修饰,则具有external链接属性,如果有static属性修饰,则具有Internal链接属性。
注意:1 static只对缺省链接属性为extern的声明才有改变链接属性的效果,如下列f。
2 为一个变量指定extern属性,就可以访问在任何位置定义的这个实体,如下列k。
3 当extern关键字用于源文件中一个标识符的第1次声明时,它指定该标识符具有extern属性,如下列b。
int a; static int b; int c(int d) { int e; static int f;//f为none连接属性 extern int k;//k本来是none链接属性,现在指定了extern属性,就有extern链接属性 extern int b;//b第二次声明为extern,不修改b的链接属性,b仍为intern链接属性 }
static关键字的作用介绍清楚了,下面写一个demo,看看怎么实现抽象数据类型,怎么实现信息隐藏,头文件addrlist.h里面声明了接口lookup_address,lookup_phone,外面可以调用,但addrlist.c文件里面的find_entry函数,外面是不能调用的,因为该函数具有static属性,即不是external链接属性。
/* ** Declarations for the address list module. */ /* ** Data characteristics ** ** Maximum lengths of the various data (includes space for the ** terminating NUL byte), and maximum number of addresses. */ #define NAME_LENGTH 30 /* longest name allowed */ #define ADDR_LENGTH 100 /* longest address allowed */ #define PHONE_LENGTH 11 /* longest phone # allowed */ #define MAX_ADDRESSES 1000 /* # of addresses allowed */ /* ** Interface functions ** ** Given a name, find the corresponding address. */ char const * lookup_address( char const *name ); /* ** Given a name, find the corresponding phone number. */ char const * lookup_phone( char const *name );
/* ** Abstract data type to maintain an address list. */ #include "addrlist.h" #include <stdio.h> /* ** The three parts to each address are kept in corresponding ** elements of these three arrays. */ static char name[MAX_ADDRESSES][NAME_LENGTH]; static char address[MAX_ADDRESSES][ADDR_LENGTH]; static char phone[MAX_ADDRESSES][PHONE_LENGTH]; /* ** This routine locates a name in the array and returns the ** subscript of the location found. If the name does not exist, ** -1 is returned. */ static int find_entry( char const *name_to_find ) { int entry; for( entry = 0; entry < MAX_ADDRESSES; entry += 1 ) if( strcmp( name_to_find, name[ entry ] ) == 0 ) return entry; return -1; } /* ** Given a name, look up and return the corresponding address. ** If the name was not found, return a NULL pointer instead. */ char const * lookup_address( char const *name ) { int entry; entry = find_entry( name ); if( entry == -1 ) return NULL; else return address[ entry ]; } /* ** Given a name, look up and return the corresponding phone ** number. If the name was not found, return a NULL pointer ** instead. */ char const * lookup_phone( char const *name ) { int entry; entry = find_entry( name ); if( entry == -1 ) return NULL; else return phone[ entry ]; }