在進入正題前我們必須了解一些概念:
標識符:標識符不僅僅代表着變量的名字,main()函數的main也是一個標識符,這點很重要。
存儲類型:即變量的存儲位置及其生存周期:
靜態區:分為兩塊
.date 已顯式初始化的全局變量了靜態變量
.bss 存放未初始化的全局或者靜態變量
注意:
靜態變量的初值是在編譯時就進行初始化了;
意思就是用static修飾的變量賦過數值的話就保存為他的初值,如果沒有初始化的話就賦值為零,且整個程序只初始化一次;
即不管static int i = 1;或者這 static int a 在程序中的什么位置;分別由編譯器初值裝入1和0保存在靜態區
注意初始化只執行一次;看如下例子:
#include <stdio.h>
void add()
{
static a;
static b = 1;
printf("%d\t",a++);
printf("%d\n",b++);
}
int main()
{
int i = 0;
for(;i<5 ;i++)
{
add();
}
return 0;
}
的結果為:
0 1
1 2
2 3
3 4
4 5
堆棧區:
棧:系統自動分配和釋放:例如局部變量函數或者代碼塊結束時釋放因為就是局部變量存儲在棧區。
堆:開發者自己生申請和釋放(例如調用void *malloc())。它的生存周期是開發者決定的。
當你使用malloc的是后被造出來,free后被銷毀。
常量區:存儲常量數據;編譯完成后到程序結束都存在,可以訪問但是不能被修改。
鏈接屬性:
假設我們有很多.c文件一起生成一個可執行文件例如:
test0.c test1.c test2.c
| | |
| | |
| | |
test0.o test1.o test2.o
| | |
——————————————鏈接
|
test
鏈接的作用就是將各個二進制代碼文件鏈接生成一個可執行文件所以不管是我們寫了多少個c文件最后都是要被合成一個的,
這個時候我們就該考慮一個問題各個文件的標識符是否公用,因此便引出了鏈接屬性。
c規定鏈接屬性分為三種:
external(全局的):各個文件訪問的是同一個標識符。
internal(局部的):標識符只被該文件中定義后的地方能訪問。
none(無鏈接屬性):沒有鏈接屬性。
作用域:即標識符能被訪問的代碼區域大小。
代碼塊作用域:在代碼塊中定義的標識符只在定義的開始和代碼塊的時候能被訪問,即使是被聲明為靜態不能使作用域擴大,這個下面會提到。
文件作用域:一般指全局變量和函數,即在整個文件中從定義的起始的位置后都能被訪問。
原型作用域:即形參的作用域,一般就是在整個函數代碼塊中有效,它的存在是防止我們多次在函數內定義一個和形參標識符的名字沖突的標識符
因為這樣我們會失去形參的值。
函數作用域:這個是用來說代碼標號的作用區域的,所以他和goto有關,呵呵,我看了一眼就忘了。
下面來看幾個關鍵字()
auto:進入程序時在棧創建,程序結束自動釋放。一般局部變量自帶auto屬性。所以用的很少。
static:
1:用於修飾局部變量時修改的是其存儲類型,使其成為靜態存儲。至於局部變量靜態存儲后的變量有什么改變參照上文的解釋和例子。但是作用域不改變。
2:修飾全局標識符時,意思是將全局變量的external屬性修改為internal。但是作用域不改變。
3:修飾函數時是修改它的鏈接屬性external屬性修改為internal。但是作用域不改變;
extern:
1.修飾變量時聲明這個變量定義在別的文件中或者本文件其他位置的external屬性的變量,一般用來修飾全局標識符(變量函數);
注意:
如果我們在標識符聲明時,一旦是在函數塊外部聲明,那么編譯器默認加多上一個external屬性,而不是extern修飾符。這很重要容易混淆。
而在代碼塊中聲明的局部變量則會被帶上一個intenral的鏈接屬性。但這不代表他只能在代碼塊的屬性是intenral的鏈接屬性賦予的。
真正的原因是因為局部變量被看作一個auto類型的變量。
register:即存儲在寄存器中的變量,寄存器有什么特點大家都知道寄存器的取數效率很高常用於重復的變量運算。注意
不能用全局變量去申請,一般默認為auto,這和全局變量的生命周期有關。
總結:千萬不能把extern和external與static與internal混淆。他們的具體解釋看上文。
狗日的公司筆試其和考試題經常拿這個來考人。就像下面這個:
#include "stdio.h"
int a=1;
int f(int c)
{
static int a=2;
c=c+1;
return (a++)+c;
}
main()
{
int i,k=0;
for(i=0;i<2;i++)
{
int a=3;
k+=f(a);
}
k+=a;
printf("%d\n",k);
}
我們只要根據上文提到的知識:把變量表示符一換,就可以了:
#include "stdio.h"
int a=1;
int f(int c)
{
static int b=2;
c=c+1;
return (b++)+c;
}
main()
{
int i,k=0;
for(i=0;i<2;i++)
{
int d=3;
k+=f(d);
}
k+=a;
printf("%d\n",k);
}
問題及解決,媽媽再也不用擔心我的學習。