《C和指针》笔记13: static关键字总结

文章讲述了C语言中static关键字在函数定义和变量声明中的作用,如何改变链接属性和存储类型,以及如何通过static实现抽象数据类型(如地址列表模块)的黑盒设计,保证模块间独立和接口的稳定性。
摘要由CSDN通过智能技术生成

这里对static关键字做一下总结,可以回顾一下前面两篇博客的文章。

《C和指针》笔记11: external和internal链接属性
《C和指针》笔记12: 存储类型(自动变量、静态变量和寄存器变量)

  1. 当它用于函数定义时,或用于代码块之外的变量声明时,static关键字用于修改标识符的链接属性,从external改为internal,但标识符的存储类型和作用域不受影响

用这种方式声明的函数或变量只能在声明它们的源文件中访问

  1. 当它用于代码块内部的变量声明时,static关键字用于修改变量的存储类型(从自动变量修改为静态变量),但变量的链接属性和作用域不受影响

用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一直存在,而不是每次在代码块开始执行时创建,在代码块执行完毕后销毁

对于1这里举个例子:

  • C可以用于设计和实现抽象数据类型 (ADT,abstract data type),因为它可以限制函数和数据定义的作用域。这个技巧也被称为黑盒 (blackbox)设计。抽象数据类型的基本想法是很简单的——模块具有功能说明和接口说明,前者说明模块所执行的任务,后者定义模块的使用。但是,模块的用户并不需要知道模块实现的任何细节,而且除了那些定义好的接口之外,用户不能以任何方式访问模块

  • 限制对模块的访问是通过static关键字的合理使用实现的,它可以限制对那些并非接口的函数和数据的访问。例如,考虑一个用于维护一个地址/电话号码列表的模块。模块必须提供函数,根据一个指定的名字查找地址和电话号码。但是,列表存储的方式是依赖于具体实现的,所以这个信息为模块所私有,客户并不知情。

  • 下一个例子程序说明了这个模块的一种可能的实现方法。头文件addrlist.h提供一些由客户使用的接口。程序addrlist.c展示了这个模块的实现。

addrlist.h

/*
** 地址列表模块的声明。
*/ /*
** 数据特征
**
** 各种数据的最大长度(包括结尾的NUL字节)和地址的最大数量。
*/
#define NAME_LENGTH 30 /*允许出现的最长名字 */
#define ADDR_LENGTH 100 /* 允许出现的最长地址 */
#define PHONE_LENGTH 11 /* 允许出现的最长电话号码 */
#define MAX_ADDRESSES 1000 /* 允许出现的最多地址个数 */ 

/*
** 接口函数
**
** 给出一个名字,查找对应的地址。
*/ 
char const * lookup_address( char const *name ); 

/*
** 给出一个名字,查找对应的电话号码。
*/ 
char const * lookup_phone( char const *name );

addrlist.c

/*
** 用于维护一个地址列表的抽象数据类型。
*/

#include "addrlist.h"
#include <stdio.h> 

/*
** 每个地址的三个部分,分别保存于三个数组的对应元素中。
*/ 
static char name[MAX_ADDRESSES][NAME_LENGTH]; 
static char address[MAX_ADDRESSES][ADDR_LENGTH]; 
static char phone[MAX_ADDRESSES][PHONE_LENGTH]; 

/*
** 这个函数在数组中查找一个名字并返回查找到的位置的下标。
** 如果这个名字在数组中并不存在,函数返回-1。
*/ 
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; 
} 

/*
** 给定一个名字,查找并返回对应的地址。
** 如果名字没有找到,函数返回一个NULL指针。
*/ 
char const * 
lookup_address( char const *name ) 
{ 
	int entry; 
	entry = find_entry( name ); 
	if( entry == -1 ) 
		return NULL; 
	else 
		return address[ entry ]; 
} 

/*
** 给定一个名字,查找并返回对应的电话号码。
** 如果名字没有找到,函数返回一个NULL指针。
*/ 
char const * 
lookup_phone( char const *name ) 
{ 
	int entry; 
	entry = find_entry( name ); 
	if( entry == -1 ) 
		return NULL; 
	else 
		return phone[ entry ]; 
}
  • 上面的程序是一个黑盒的好例子。黑盒的功能通过规定的接口访问,在这个例子里,接口是函数lookup_addresslookup_phone。但是,用户不能直接访问和模块实现有关的数据,如数组或辅助函数find_entry,因为这些内容被声明为static
  • 这种类型的实现威力在于它使程序的各个部分相互之间更加独立。例如,随着地址列表的记录条数越来越多,简单的线性查找可能太慢,或者用于存储记录的表可能装满。此时你可以重新编写查找函数,使它更富效率,可能是通过使用某种形式的散列表查找来实现。或者,你甚至可以放弃使用数组,转而为这些记录动态分配内存空间。但是,如果用户程序可以直接访问存储记录的表,表的组织形式如果进行了修改,就有可能导致用户程序失败。
  • 黑盒的概念使实现细节与外界隔绝,这就消除了用户试图直接访问这些实现细节的诱惑。这样,访问模块唯一可能的方法就是通过模块所定义的接口。

参考

  1. 《C和指针》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值