Feedback
2009-08-20 22:34 |
(S)(*(sa+100*sizeof(S))).a();
這個表達式有2個小問題, 其他都到位。
由此, 可以給他解釋另一個更經典的……
static_cast<S*>(0)->a();
-_-; ...
回復 更多評論
2009-08-20 22:57 |
不管怎么說,這個都是錯誤的。而且很多時候都是致命的。
回復 更多評論
2009-08-20 23:21 |
@胡友蒙
代碼中只出現了無效地址, 但并沒有解引用。
>而且很多時候都是致命的
這樣做至少在i386上是100%不會出現任何問題, 所以, 不用說得這么嚇人。
回復 更多評論
2009-08-21 01:24 |
瞎猜是沒用的,直接反匯編就一目了然了。這是編譯器優(yōu)化的結果。靜態(tài)變量就直接訪問了。
回復 更多評論
2009-08-21 02:05 |
這種只讀內存的代碼不會有什么問題。而且你這個代碼訪問的是靜態(tài)內存sum。
回復 更多評論
2009-08-21 10:20 |
在某編譯器下,我見過這樣的怪事。聲明了某類的指針p,但并沒有將其指向任何對象,卻可以調用這個類里的非靜態(tài)方法(如p->func( );)。當然,這個方法里邊有訪問成員變量的地方,在那里,程序崩潰了。
回復 更多評論
2009-08-21 10:23 |
int main()
{
s *ss = new s();
ss->a();
ss = NULL;
ss->a();
return 0;
}
可以試下這個測試函數,原理是一樣的,在于this指針.....
回復 更多評論
2009-08-21 10:59 |
原因是你沒有對無效的地址進行寫操作。你弄個虛函數試試
回復 更多評論
2009-08-21 11:25 |
對于錯誤代碼的處理,不同的編譯器會使用不同的手法, 所以這樣的代碼還是少寫
回復 更多評論
2009-08-21 11:40 |
我看不懂~~~
回復 更多評論
2009-08-21 17:18 |
是否該大方過
回復 更多評論
2009-08-23 09:29 |
void a()
{
cout<<sum<<endl;
//因為這段代碼沒有訪問this指針指向的內存
}
回復 更多評論
2009-08-23 16:55 |
學習啦...
回復 更多評論
2009-09-01 21:23 |
代碼中出現無效地址,那通過無效地址去訪問有效地址按理說也是錯的喲~~
如果不解引用就不出錯的話,但是博主的解釋中就有解引用了。
還是不會匯編啊,哪天抽空看看,看看優(yōu)化的代碼
回復 更多評論
2009-09-01 21:31 |
@莫失莫忘
你是從那句解釋中看出有解引用一說的?
回復 更多評論
2009-09-01 21:37 |
@莫失莫忘
靜態(tài)成員本來就可以通過
1. 類名
S::sum
2. 實例
S s;
s.sum;
兩種形式訪問, 毫無區(qū)別, 推薦第1種形式。
this->sum 依然是 S::sum, 而不會是s的非靜態(tài)成員。
它根本就沒有非靜態(tài)的sum, 難道編譯器還因為this->sum專門給它再加這么一個非靜態(tài)sum么?
回復 更多評論
2009-09-01 21:49 |
在那里解引用?自己去看看博主的解釋吧!
-----------------------------------
OwnWaterloo誤解了,至少我的編譯器沒那么智能——第二個回復就不解釋了,這只是測試下非靜態(tài)成員函數對于靜態(tài)成員變量的訪問。
回復 更多評論
2009-09-01 22:05 |
@莫失莫忘
> 自己去看看博主的解釋吧!
我又看了一遍。
只有對S::sum有語意上以及實現上的解引用。
對 sa[100].a(); 有語意上的解引用。
Chuck 這文章正是想得出 —— s[100].a(); 只存在語意上的解引用, 實際上沒有進行解引用, 所以才不會出錯 —— 的觀點。
> 代碼中出現無效地址,那通過無效地址去訪問有效地址按理說也是錯的喲~~
> 如果不解引用就不出錯的話,但是博主的解釋中就有解引用了。
依然不明白你在說什么……
回復 更多評論
2009-09-01 22:12 |
C++中對于數組越界之類的問題是不會在編譯時進行檢查的,如果代碼中越界了,那編譯不會出錯。但是如果運行就會報錯:訪問未初始化的數據之類的。而那句:
sa[100].a();
因為無論如何一個函數在內存中只有一個,所以這句解釋為:
S:a();
更具體點就是這樣了:
S::a(&S[100]);
而S[100]是一個無效地址,但是也沒關系。
cout<<sum<<endl;
這句打印的是全局變量,這就不涉及越界問題了。
------------------------我是純潔的分割線大人----------------------
問一下:
OwnWaterloo,你是不是一直等在CPP BLOG上?
回復 更多評論
2009-09-01 22:14 |
不明白無所謂,我的測試代碼改了不少,重要的是:
我覺得現在我的解釋應該是正解滴了
回復 更多評論
2009-09-01 22:22 |
語意上的解引用?實際上的解應用?
真心話哦:這個解釋確實是讓我漲見識了。這我同意!
我的原話話:代碼中出現無效地址,那通過無效地址去訪問有效地址按理說也是錯的喲。
是因為:在JAVA中,通過無效的地址去訪問是絕對會出錯的。當然了,在CPP論壇咱不說JAVA,這只是常人的一個思維:通過不存在的去訪問當然會出錯,所以博主的同學才會有那個問題。
回復 更多評論
2009-09-01 22:42 |
@莫失莫忘
> 如果代碼中越界了,那編譯不會出錯。但是如果運行就會報錯
對數組越界, C++標準中的描述是“未定義”。
據說有一些平臺(我只用過i386和ppc), 確實會檢查無效地址——甚至只是獲取,而沒有進行操作, 例如:
int a[12];
int* p = &a[13]; // 就會引發(fā)錯誤。
而在i386下, 后一句代碼只會產生一個無效(無效的準確含義是越界)地址, 不會引發(fā)錯誤 —— 甚至對無效地址的訪問(讀寫)是否會引發(fā)錯誤, 都要看運氣。
首先, &a[13]肯定不是nullptr。 nullptr檢測區(qū)就不會起作用。
其次, vc可能會在a[12]附近安插一些guard。
int read = *p; // 無法檢測
*p = 1212; // 檢測出寫, 如果guard的恰好是1212,越界寫都判斷不出
guard的值好像是0xcc。
三, vc的release配置不會安插guard。
四, 還有一種能檢測到錯誤的情況。
p 指向的地址還沒有被保留或提交。
因為i386 下windows的棧通常是向下增長,
p = &a[ /* 這里需要一個很大的正數 */ ]; 才能越過棧底, 達到保護區(qū)。
但
p = &a[ /* 如果這里是負數 */ ] ; 越過以提交的棧頂, 達到保護區(qū)就容易許多。
如果p誤指的不僅僅是棧上變量, 那還可以增加一些錯誤檢測的機會。
沒有被保留與提交的頁, 讀寫都會錯。
已提交的頁, 還得看頁的保護屬性。
說了這么多, 就是想說所謂的“運行就會報錯”, 是不靠譜的。
如你所見, 上面已經列舉出許多運行時不會報錯的情形——這種情形還不少。
所以, 大家寫代碼還是要按照規(guī)范來……
為什么這種不合乎規(guī)范的代碼不會出現錯誤, 只能作為茶余飯后的談資……
回復 更多評論
2009-09-01 22:58 |
@莫失莫忘
> 語意上的解引用?實際上的解應用?
這真的不是搞笑。
S sa[12];
int ia[12]
那么sa[100]; ia[26]; 這2
個表達式, 按C++的說法, 其結果類型就是 S& 和 i&。
如果給一些C程序員看, 他們還會告訴你,
sa[100]; 等效于 *(sa+100);
ia[26]; 等效于 *(ia+26);
所以, 我說這里有一個語意上的解引用。
但實際在, 在i386下, msvc和gcc編譯器, 都不會理睬
sa[100]; ia[26]; 這么一個孤單的表達式。
只有當
int i = ia[26]; /* int i = *(ia+26); */ 讀
ia[26] = 1212; /* *(ia+26) = 1212 */ 寫
的時候, 才會真正產生"解引用"的代碼 —— mov指令
并且, 只有 int* p = ia + 26; p的地址沒有相應權限(將未提交也理解為缺陷缺失的話), 才會引發(fā)錯誤。
對自定義類型:
sa[100].a(); 調用處都不會產生解引用代碼。
只有在
S::a() { // 定義處
才有可能產生解引用代碼—— 如果操作非靜態(tài)數據成員的話。
}
按C++標準來說, 表達式:
sa[100]; ia[26];
已經是未定義行為了。 只是在i386上, 通常不會造成什么問題。
又因為S::a()沒有操作非靜態(tài)數據成員, 就不會產生實際的mov指令, 也不會有問題。
-----------------------------------------
sum是S的靜態(tài)數據成員, sum本來就是在靜態(tài)存儲區(qū)中的。
即使是按C++標準, 無論是
S::sum
this->sum
都是對S::sum——靜態(tài)存儲區(qū)中的一個變量——的操作。
沒有問題是自然的。
for (int i=0;i<1212;++i) sa[i].sum
只要 sa[i]表達式不出問題, sa[i].sum 依然是訪問的S::sum , 沒有問題還是顯然的。
回復 更多評論
2009-09-01 23:11 |
@莫失莫忘
> OwnWaterloo,你是不是一直等在CPP BLOG上?
有個"有回復時郵件通知我"。
我通常都開著郵箱, so ……
> 在JAVA中,通過無效的地址去訪問是絕對會出錯的
java中不能隨意操作指針。 除了null, 如何能產生一個無效地址?
array 都是一個所謂的"對象", 記錄著大小, 隨時可以檢查邊界。
JNI可以嗎?
> 這只是常人的一個思維:通過不存在的去訪問當然會出錯
這是javaer的思維。
現在使用的計算機中, 馮諾依曼架構是主流。
所以, 當cpu真正進行運算的時候, 一切都是地址。
硬件會提供一些手段, 區(qū)分一些地址是否有效。
但通常是軟件, 通過"指令流"而產生"控制流", 來判斷某地址是否有效。
C/C++不提供這些保姆功能。
這個例子充分說明了,正因為沒有這些保姆功能, C/C++中, 程序員要尤其小心, 不能依賴于"編譯器、OS、CPU"提供的"功能有限、可有可無(標準未定義)"的保護手段, 而要自己注意越界問題。
回復 更多評論