好啦,我们接着上一节继续,上节说到了bss vs data,那我们就从变量开始说起。首先,有几个问题:
你知道automatic variable 和 static variable的区别吗?你知道static放在function内部和外部的区别吗?你能说说definition和declaration有什么区别吗?或者问一个看起来貌似最最简单的额问题,你知道什么是变量吗?
如果一知半解、不得要领,那么希望下面写的能让你醍醐灌顶。OK,我们先来回答这个所谓的最简单的问题:什么是variable?
- A program variable is an abstraction of a computer memory cell or collection of cells;
- A variable can be characterized as sextuple of attributes: <name, address, value, type, lifetime, scope>.
搞清这点,尤其是第二点,对后面理解变量之间的差异至关重要。(来自:http://groups.engin.umd.umich.edu/CIS/course.des/cis400/maxim/lectures/chp4.htm)
OK,既然我们知道了什么是变量,那么来看 variable types。那你知道什么是变量类型吗?int、char?extern、static?不不,都不是。记住了,C语言的variable types(变量类型)主要有两种:
- local variables
- global variables
怎么样,很诧异吧?那么,你又疑惑了,int、double、char、void这些又是什么呢?听好啦,这个叫data types(数据类型),很显然,variable types要宏观的多,data type只表示单个数据嘛!那接下来的extern、static又是什么呢?storage classes,可以翻译成存储类别,但我认为还是不翻译的好。其实,从前带给我们困惑的往往是这个storage class,好啦,那我们就看看它里面到底分为哪些东西吧!我们一个个说。
1. auto(automatic)
auto variable,经常有人翻译成自动变量。auto is the default variable for all local variables.
{
int Count;
auto int Month;
}
记住一句话,所有的local variables都是auto variables。上面的例子中,其实都是auto,只不过一个写出来一个没写出来罢了!
2. register
寄存器变量。Register is used to define local variables that should be stored in a register instead of RAM. 为什么用它呢?快呗!从寄存器取数显然要比从内存中快嘛!但是,它有两个很严重的限制:
(1) maximum size equal to the register size;(2) cannot have '&' operator applied to it(it has no memory location).
其实我认为,这两个限制够残忍的了。所以说,需要quick access(such as counters)的变量才使用。但因为register数量有限,不是你想用就给的(意思是虽然你用register声明但不一定真的放在寄存器里),这当然要看系统限制啦。
{
register int Miles;
}
当然注意一点啦,register还是为local variable准备的!
3. static
静态变量,这个有时候最具迷惑性了。迷惑性的来源当然是函数外的static和函数内的static啦!话不多说,第一步当然是看定义:static is the default storage class for global variables. 天呐,正好与auto对应。这个意思是说,所有未加修饰的local variable都是auto的,而所有未加修饰的global variable都是static的!看下面的代码;
static int Count;
int Road;
{
printf("%d\n", Road);
}
这两个变量竟然都是static的!那么他们存放在哪里呢?bss?data?废话,当然是bss啦,他们uninitialized,没被初始化嘛,自动初始化为0啦!
但是,如果static放在函数内部会有什么区别呢?我们来看,还记得刚开始提到变量的sextuple吗?<name, address, value, type, lifetime, scope>。scope!bingo~如果static放在function外面,那么就敞开胸怀让你看咯,但是,a bigger scope means more exposure to errors! 这个观点你认同不?要知道,当link的时候,引入了外来模块,比如说万一和定义的static变量name冲突了呢?如果放在函数内部就没事,因为其它模块们看不到它嘛!(http://stackoverflow.com/questions/15808049/what-is-the-use-of-static-local-variable-when-we-can-get-a-global-variable-at-th)
那究竟static放在里面和外面有什么区别呢?假如它们都是initialized,那么他们的lifetime(生命周期)是一样的,唯一不同的就是scope(作用域)啦!当然,因为都是initialized,他们当然都放在data区,而不是像一般的local variable一样放在stack frame中啦!
void func(void);
static count=10; /* Global variable - static is the default */
int main()
{
while (count--)
{
func();
}
return 0;
}
void func( void )
{
static i = 5;
i++;
printf("i is %d and count is %d\n", i, count);
}
——————————————————————————
This will produce following result
i is 6 and count is 9
i is 7 and count is 8
i is 8 and count is 7
i is 9 and count is 6
i is 10 and count is 5
i is 11 and count is 4
i is 12 and count is 3
i is 13 and count is 2
看这个程序,关于这个static的用法我们很常见:很清晰,放在函数内部的static variable仅在最初时initialized,后面每次的function call不会对其再次进行初始化。当然,初始化后的i保存在data段。
还有一点非常重要的(very important!!!)关于static的:
char *func(void);
main()
{
char *Text1;
Text1 = func();
}
char *func(void)
{
/*case 1: */
char Text2[10]="martin";
/*case 2: */
static char Text[10]="martin";
return(Text2);
}
我把case 1和case2合并在了一个程序里,其实本应在两个程序中。试想,如果执行case 1的情况会return什么?who knows!想想变量的lifetime。在case 1中 char *Text2是auto变量,return过后随即就被清除,天知道它return了什么啊!但是case 2中,static char *Text2的lifetime是整个程序的执行过程,当然会正常返回!这一点经常被考察,其实说实话就是考你生命周期和存储位置的相关知识啦,智者不惧嘛!
喂喂!等等!在说第四个storage class——extern之前,先得把一个变量或函数的definition和declaration了解清楚!
Definition means a variable or function is defined in reality and actual memory is allocated.
Declaration means just giving a reference of a variable or function.
简单的说呢,就是定义是分配了空间,声明只是对compiler说:这个variable或function在其它地方已经定义过啦 and will be provided at the time oflinking. 就比如说上面的那个程序,第一行 char *func(void); 显然是声明(declaration),它告诉编译器别急,definition在下面呢!所以下面的definition分配了空间,细化了函数。
好啦,可以看extern啦!
4. extern
Extern is used to give a reference of a global variable that is visible to ALL program files. 注意是global,凡是带extern的都不能被初始化,知道啥意思吗?(When you use 'extern' the variable cannot be initalized as all it does is point the variable name at a storage location that has been previously defined.)因为在别处已经定义好了,extern只是把它引用过来罢了!
这个例子就是extern,extern doesn't mean outside the current scope, it means an object with external linkage. An auto variable never has external linkage.(看,又来了,extern只用于global variables。)
当然类似的例子很多。stackoverflow上一抓一大把,搞清了原理,则一通百通~
好啦,四种storage classes已经说完啦,理解它们的前提是清楚上一节中一个C程序的空间存储,希望我讲得还算清楚!
那么,还剩一个东西,什么呢?const!
是的,constant是啥?常量呗!
A constant is usually just a written version of a number. 你看,这说的多么简洁,就是用一个东西代替一个"数"嘛!直接看例子:
'\n' newline
'\t' tab
'\\' backslash
'\'' single quote
'\0' null ( Used automatically to terminate character string )
看,上面的这些是character constants;
int const a = 1;
const int a =2;
这些也是constants,here,const放在前后都无所谓;
#define TRUE 1
#define FALSE 0
#define NAME_SIZE 20
这些还是constants,更加灵活的定义方式。
我们接着看下面的声明:
void strcpy(char *buffer, char const *string);
怎么样,这个经常见到吧,这个const放在这里是干啥的呢?This says simply that the function is not going to change the value of the parameter. 意思就是函数根本就没打算改变这个值,别无它意啦!
那么,还有const修饰函数,修饰返回值呢?我们在这儿先不提啦,总会遇到的!
本文的主题框架来自:http://www.tutorialspoint.com/ansi_c/c_storage_classes.htm
下面是长长的分割线
——————————————————————————————————————————————
今天这可谓是精彩不断呐,终于彻底搞清了auto、register、static、extern、const,但是当static和const修饰函数呢?仍然是雾里看花~不急,一点点来嘛。明天开始第八章!