符號常量:
1.用#define定義的宏常量 進入編譯階段前就被替換成多代表的字面常量,所以本質是字面常量
2.用const定義的常量
C語言中,const定義的是不能讓你個修改的量,會給它分配存儲空間(外鏈接)
C++中,基本數據類型的常量,編譯器放在符號表中,不分配存儲空間,ADT/UDT的const對象則需要分配存儲空間。默認內鏈接
特殊情況:強制聲明爲extern的符號常量或取符號常量的地址也會分配存儲空間以滿足用戶的需求。
好玩的代碼
1 #include<iostream>
2 using namespace std;
3 class A{
4
5 public:
6 A():n(100){}
7 int n;
8 };
9 int main()
10 {
11 const int a=1;
12 cout<<a<<endl;
13 int* p=(int*)&a;//取常量的地址
14 *p=2;// 迂迴修改
15 cout<<*p<<endl;//2,修改的是拷貝內容
16 cout<<a<<endl;//1,原始常量沒有變化
17
18
19 const A m;
20 A* pa=(A*)&m;//去除常數屬性
21 pa->n=1000;
22 cout<<m.n<<endl;//1000,修改const對象成功
23 cout<<pa->n<<endl;//1000,“迂迴修改成功”
24
25 }
基本常量在符號表中,編譯器會重新在內存中創建一個拷貝,你通過其地址訪問的就是這個拷貝的常量,而不是原始常量
對於構造類型的const 常量,實際它是編譯時不允許修改的常量,因此你可以繞過編譯器的靜態安全檢查機制,在運行是改變它的值。
外鏈接:C語言默認是外鏈接,分配存儲,你不可在兩個或以上的編譯單元中同時定義一個符號常量(重複定義錯誤)
內鏈接:C++默認,可以定義在頭文件中,編譯器會認爲他們是不同的符號常量,因此每個編譯單元會在獨立編譯是爲他們分配存儲空間,然後在鏈接是合併。
契約性常量
契約性const對象的定義未使用const關鍵字,但可以被看作一個const對象
void print(const int& n)
{
cout<<n<<endl;
}
int main()
{
int n=1;
print(n);
}
枚舉常量
C++/C的構造類型enum實際上用來定義一些相關常量的集合,標準C++/C規定枚舉常量可以擴展,並非受限一般整數範圍。
enum Gigantic
{
SMALL=0;
GIGANTIC=10000000000
}
幾點建議:
儘量使用含義直觀的符號常量來表示那些將在程序中多次出現的數字或字符串
C++中將需要對外公開的常量放在頭文件中,不許要公開的常量放在定義文件的頭部,爲便於管理,可以把不同模塊的常量集中存放在一個共用的頭文件中。
某一常量與其他常量密切相關,應該在定義中包含這種關係,不應給出一些孤立的值
const float RADIUS-100; const DIAMETER=2*RADIUS;
儘量使用const避免define帶來的邊際效應,純字符替換
我的發現:
1 #include<stdio.h>
2 int main()
3 {
4 const int a=123;
5 printf("%d\n",a);
6 int* p=(int*)&a;
7 *p=456;
8 printf("%d\n",a);
9
10
11 }
上面這段C代碼:
C++編譯器編譯結果: 123,123 編譯器進行優化,後面的n一律用n代替,改成volatile const int a=123, 則不會優化,每次輸出從n的內存讀取
C編譯器編譯結果:123,456 不會進行優化。