1. 聲明和定義
函數和變量的聲明不會分配內存, 但是定義會分配相應的內存空間
函數和變量的聲明可以有很多次, 但是定義最多只能有一次
函數的聲明和定義方式默認都是 extern 的, 即函數默認是全局的
變量的聲明和定義方式默認都是局部的, 在當前編譯單元或者文件內可用
了解聲明和定義對static和extern的理解有輔助作用。比如extern就是在一處定義,其他文件都只需要聲明即可,不可重復定義。
2. static& extern
2.1 static
一般局部變量是存儲在棧區的,局部變量的生命周期在其所在的語句塊執行結束時便結束了。但如果用static修飾局部變量,那么這個變量就不會存儲在棧區而是放在靜態數據區,其生命周期會一直持續到整個程序結束,該變量只在初次運行時進行初始化,且只進行一次,但是它的作用域只能是在函數里面如下:
void print(){
static int z = 100;
z++;
cout << z <<endl;
}
int main(){
print();
print();
print();
return 0;
}
局部靜態變量z只能在本文件的print函數里面訪問,一旦超出作用域范圍,就無法訪問。
如果是static修飾的全局變量,且實現的函數寫在頭文件(h)中,在其他文件也可以訪問,如下:
// a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
static char str[] = "hello";
namespace sextern {
void print1();
void Fun1();
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}
#endif // A_H
//b.h
#ifndef B_H
#define B_H
namespace sextern{
void Fun2(){
str[0] = 'o';
}
void print2(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
#endif // B_H
//main.cpp
#include "a.h"
#include "b.h"
using namespace sextern;
int main(int argc, char *argv[])
{
sextern::Fun1();
print1();
sextern::Fun2();
print2();
print1();
return 0;
}
//結果如下
/*
* value lello
* address 0x601058
* value oello
* address 0x601058
* value oello
* address 0x601058
* 按 <RETURN> 來關閉窗口...
*/
發現將static全局變量寫在頭文件中,所有文件的頭文件的操作都會共享這個變量。
但如果是在源文件(cpp)中去操作這個靜態全局變量,則這個靜態全局變量只能在當前文件有效,但是在另外一個文件訪問此靜態變量,會是該變量初始的默認值,不會是其他文件中修改的值,雖然它們有相同的初始內容,但是存儲的物理地址並不一樣。如下:
//a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
static char str[] = "hello";
namespace sextern {
void Fun1();
void print1();
}
#endif // A_H
//a.cpp
#include "a.h"
namespace sextern {
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str << endl;
cout << "address " << &str <<endl;
}
}
//c.h
#ifndef C_H
#define C_H
#include<iostream>
using namespace std;
namespace sextern {
void Fun3();
void print3();
}
#endif // C_H
//c.cpp
#include "c.h"
#include "a.h"
namespace sextern {
void Fun3(){
str[0] = 'o';
}
void print3(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}
#include "a.h"
#include "c.h"
using namespace sextern;
int main(int argc, char *argv[])
{
sextern::Fun1();
print1();
sextern::Fun3();
print3();
print1();
return 0;
}
//結果如下
/*
* value lello
* address 0x602064
* value oello
* address 0x60205e
* value lello
* address 0x602064
* 按 <RETURN> 來關閉窗口...
*/
在a.h的頭文件中定義了一個靜態的全局變量x,不同文件的函數fun1和fun3會為每個包含該頭文件的cpp都創建一個全局變量,但他們都是獨立的,只在該cpp文件共享該變量。所以一般定義static全局變量時,都把它放在原文件中而不是頭文件,從而避免多個源文件共享,就不會給其他模塊造成不必要的信息污染。如果想要在不同文件共享同一個全局變量,這個時候就要用到extern。
2.2 extern
當在某個文件定義了一個全局變量,如果要在另一個文件去使用該變量,如果再次去定義,則會出現重復定義的問題,這個時候就需要使用到聲明,對該變量的聲明告訴編譯器該變量在其他文件中已經定義,在此處要去引用它。上述的代碼改成如下形式:
//b.h
#ifndef B_H
#define B_H
char str[] = "hello"; //定義一個全局變量
#endif // B_H
//a.h
#ifndef A_H
#define A_H
#include<iostream>
using namespace std;
extern char str[];
namespace sextern {
void Fun1();
void print1();
}
#endif // A_H
//a.cpp
#include "a.h"
namespace sextern {
void Fun1(){
str[0] = 'l';
}
void print1(){
cout << "value " << str << endl;
cout << "address " << &str <<endl;
}
}
//c.h
#ifndef C_H
#define C_H
#include<iostream>
using namespace std;
extern char str[];
namespace sextern {
void Fun3();
void print3();
}
#endif // C_H
//c.cpp
#include "c.h"
namespace sextern {
void Fun3(){
str[0] = 'o';
}
void print3(){
cout << "value " << str <<endl;
cout << "address " << &str <<endl;
}
}
//結果如下
/*
* value lello
* address 0x602058
* value oello
* address 0x602058
* value oello
* address 0x602058
* 按 <RETURN> 來關閉窗口...
*/
參考資料
