0x00 最初的起點
首先是一道爛大街的題目:以下四個變量有什么區(qū)別?
答案很簡單:
1. v1是一個指針常量愁溜,即指針?biāo)赶虻闹挡豢筛淖兾迳侵羔標(biāo)赶虻牡刂房梢愿淖儭?/h5>
2. v2和v1相同蕉世。
3. v3是一個常量指針,即指針?biāo)赶虻膬?nèi)存地址不可改變耕皮。
4. v4是一個指向常量的常量指針,即無論是指向的內(nèi)存地址撑碴,還是內(nèi)存地址中的值都是不可改變的。
可以看到叹话,這個基本上就是依靠記憶的東西偷遗,并沒有什么理解上的難點,只是記住之后沒過一段時間可能就又混淆了驼壶。
記憶方案一
1.如果const位于的左側(cè)氏豌,則const就是用來修飾指針?biāo)赶虻淖兞浚粗羔樦赶驗槌A浚?br> 2.如果const位于的右側(cè)热凹,則const就是修飾指針本身泵喘,即指針本身是常量泪电。
恩... 似乎很有規(guī)律的樣子,但是我記性很差纪铺,這種規(guī)則對我來說還是太繞相速,過一段時間就不確定會不會記反了。
記憶方案二
Bjarne在他的The C++ Programming Language里面給出過一個助記的方法:
把一個聲明從右向左讀霹陡。
char * const cp; ( * 讀成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
恩和蚪。這樣確實大大的降低了記混的情況了,但是雖然這種方法已經(jīng)很簡單了烹棉,但是對于英語不是母語的人來說攒霹,還是需要繞一層的,那么有什么更加簡單的記憶方法嗎浆洗?
記憶方案三
const修飾前面的關(guān)鍵字催束,只有當(dāng)const開頭時才修飾后面的關(guān)鍵字
即:當(dāng)const前面是char int
之類的類型關(guān)鍵字時,表示修飾的是指針?biāo)赶虻膬?nèi)容伏社;而當(dāng)前面的是指針運算符(*
)的時候抠刺,那么表示修飾的是該指針;當(dāng)const位于表達式首位時摘昌,請參考第一條速妖。
0X01實現(xiàn)機制
其實const關(guān)鍵字并沒有多么復(fù)雜的實現(xiàn)方法,只是在編譯器的層面做了modify的限制聪黎,而const變量和非const變量在runtime期間其實并無卵分別罕容,最好的證據(jù)就是編譯過程中的匯編代碼了,證據(jù)如下:
首先我們有兩段簡單到媽都不認得的C++代碼:
代碼一
#include <iostream>
using namespace std;
int main()
{
int a = 100;
return 0;
}
代碼二
#include <iostream>
using namespace std;
int main()
{
const int a = 100;
return 0;
}
這兩段代碼唯一的區(qū)別就是稿饰,一個int變量有const修飾锦秒,而另一個int變量沒有const修飾。OK喉镰,接下來我們編譯成匯編旅择,使用下面的命令:
g++ -S demo.cpp
編譯之后得到的匯編代碼對比圖如下所示:
我們可看到,兩者并無什么不同侣姆,也就是說生真,匯編并不會對const的變量做什么特殊的處理,const只是在編譯的層面給程序做了限制捺宗。
但是柱蟀,這里又有一個問題,當(dāng)我們把代碼修改成下面那樣的時候:
代碼一
#include <iostream>
using namespace std;
int main()
{
int a = 100;
cout << a << endl;
return 0;
}
代碼二
#include <iostream>
using namespace std;
int main()
{
const int a = 100;
cout << a << endl;
return 0;
}
這里的代碼與上面的代碼的區(qū)別無非是偿凭,訪問了a的值产弹,按照上面的理論派歌,編譯后的代碼應(yīng)該沒有不同弯囊,但是世事難料痰哨,對比圖如下:
我們可以看到竟然還是存在差別的,但是根據(jù)查閱資料和個人猜測匾嘱,我認為可能的原因是:const的變量存儲的時候確實沒有特殊處理斤斧,但是在取值時,并不會訪問const變量的內(nèi)存地址霎烙,而是通過一個全局符號表(symbol table)替換了該值
撬讽,所以才會出現(xiàn)這樣的匯編代碼的差別。
0X02 最后說的話
說到底還是不懂匯編悬垃,有空也可以研究一下游昼,如果有匯編大神路過,也請不吝賜教尝蠕!