考慮到以下代碼:
int A[5] = {0, 1,2,3,4}。
int i=1;
int test = A[i];
這段代碼產生的MIPS匯編將把i左移2位以乘以4,因為我們取的是一個int(4位元組)。我完全理解這一點。
現在,如果我們設定
int i = -1; /or 任何負數。
產生的匯編實際上將是相同的。但在這里,我們將一個負數移位2位,實際上可能回傳一個正數。所以,我的問題是,A[negative_number]不會將地址偏移這個負數,但它會產生一個有些隨機的結果,對嗎?
uj5u.com熱心網友回復:
左移-12位,得到-4,這是正確的位元組偏移量,添加到-1st位置。
只有當i非常大,導致結果溢位時,左移才會產生一個正數。但是只有當你試圖訪問超過第-229個索引時才會發生這種情況(假設是32位的ints),當然,首先要求的索引太大(小?
順便說一下,只有當你從一個處于物件中間的指標開始時,訪問一個負數的索引才是有效的,而且負數的索引還在訪問有效的記憶體。A[-1]將呼叫未定義的行為。一個更好的例子是:
int *p = &A[3] 。
int i = -1;
int test = p[i];
這里p[-1]決議為(&A[3])[-1],相當于A[2]。這是一個有效的索引,所以p[-1]是合法的。
另外,雖然在匯編代碼中沒有問題,但需要注意的是,在C語言中左移負數是未定義的。不要試圖在你的C代碼中寫-1 << 2。編譯器可以代表我們這樣做,但我們不允許自己寫。
如果你把100001向左移動一次呢?你會得到000010,這在我的書中是正數。
這只有在ints是6位寬的情況下才會發生。根據 C 標準,它們必須至少有 16 位寬,而且在現代計算機中通常是 32 位,有時是 64 位。
假設我們是在一個 16 位的系統上。100001實際上將是這兩個數字中的一個:
0000000000100001. 這是33,一個正數。1111111111100001. 這是-31,一個負數。向左移位將保留所有領先的1位,并保持負數。
uj5u.com熱心網友回復:
A[-1]確實指定了記憶體中A[0]之前的元素,如果在C標準使用的計算模型中存在這樣一個元素的話。如果A是一個陣列,它就不會這樣做,但是如果A是一個指標,它就會這樣做:
int X[] = { 10, 11, 12, 13 }。
int *A = &X[2] 。
printf("%d
", A[0]); // Prints "12".
printf("%d
", A[-1]); //列印 "11".
編譯器為A[-1]生成的指令將正確計算地址,無論它們使用移位、倍數或其他計算方法,只要A[-1]是計算模型中的有效物件。
只有在出現溢位的情況下,對一個負數進行左移才會產生一個正數。
(C標準以簡單的抽象計算機的方式指定了行為,其中所有的物件都存盤在記憶體中,而對一個物件的每一次使用都是從其記憶體中加載或存盤的。在實踐中,編譯器會進行優化,并可能將物件保存在暫存器中而不是記憶體中,以及其他優化。任何具有定義行為的程式的最終結果都應該是與抽象模型中的程式相同的行為,但編譯器的實作方式可能與C標準的描述方式大不相同。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/320412.html
標籤:
