從printf說開去 四

2021-05-25 05:18:41 字數 1347 閱讀 5974

(接上文)

對於函式:

float sumfunf(int num, …)

return (float)result;

}第乙個固定引數傳入2,代表累加的數字個數為2,不定引數部分傳入1和2作為引數,呼叫函式看看結果:

float r = sumfunf(2, 1, 2),此時的r值也是不確定的。(如果用vc7以上做乙個最簡的控制台測試,大部分情況下r的值返回應該是0。)

sumfunf函式在處理時,首先取得不定引數部分的偏移量,接下來按照「傳入的引數都是double」這個假定進行處理。而sizeof(double)為8,也即是說,

函式期望以8個位元組為單位讀取堆疊資料,此時的堆疊情況如下:

棧頂———————————————————————————————

第乙個引數num(用於表示不定引數個數),占用空間4位元組。值為0×00000002

不定引數起始位址–>  ———————————————————————————————-

0×00000001 (4位元組)

————————–

0×00000002 (4位元組)

————————–

…其他已經入棧的資料

通過看上面這個堆疊示意,問題應該已經很明顯了,sumfunf函式在取引數的時候是期望以double為單位獲取資料的,機器並不知道這個資料是什麼「型別」,

機器按double(8個位元組)占用的位元組空間讀取,這樣,傳入的1、2這兩個值被當成了乙個資料讀出來,按照double的規則進行處理,讀出的值為:0×0000000200000001 (此例中使用big endian序)。

但是,問題出現了,這才讀出乙個引數,我們還有乙個引數到**去讀呢?

sumfunf函式在讀出第乙個引數後,將其值累加至result變數中,在讀取第二個引數時,取值的位址範圍已經超出了我們傳入的資料,然而程式並不會就此出錯,恰好在這幾個引數之後的堆疊位址中,資料是有效的!

這些資料可被正確的訪問,因此,函式在處理第二個引數會繼續順序讀取8個位元組!這8個位元組的值作為第二個引數進行處理,回顧一下雙精度浮點數的計算方式,對於0×0000000200000001這樣乙個數來說,是近乎於0的,因此,最後返回的值是不是為0,就取決於函式從堆疊中順序讀取出來的第二個引數,而這個值是不確定的!我們之所以看到返回值為0.000000,是因為對於這個簡單程式而言,在特定的環境下,大部分情況下,讀取出來的第二個不定引數在轉換為double後,也是接近於0的。

回到printf(「%f」,10/3);的問題來說,產生大家看到的不確定結果也是這個原理。

對於printf(「%f」, 10/3, 0×40080000);這個能獲得3.000000的結果,不妨嘗試先自行分析一下。

(未完待續)

從PDF說開去

最近想研究一下pdf。pdf從ps脫胎而來,秉承ps強大的描述能力,以其精美的 效果,已幾乎成為internet時代的 標準文件格式 說pdf是 標準 可能有人不愛聽,見後文 如果軟體能夠支援自動輸出 匯出 為pdf格式文件,無疑軟體的專業化色彩會更濃一些。人之常理 你推出一種文件格式,使用的人 軟...

從時間說開去

非常羨慕那種需要很少睡眠,思維敏捷,做事雷厲風行的人。之所以羨慕,是因為我不具備。我做為乙個需要很多睡眠並且睡眠質量不高的人,做事也一般是三思而後行,遇事也慢人半拍,對於我這樣乙個人,怎樣合理安排時間就成了很大的問題。從小就喜歡利用一大片的時間,專注的去做一件事情。所以,在上了大學以後,看到我的同學...

從「盜版」說開去

發行了幾年的共享軟體 vb原始碼之友 終於被盜版了,雖然共享軟體沒有給我帶來讓人羨慕的財富,但是這幾年來也有不少的正版使用者群在默默的支援著我繼續推出我的軟體產品。我的心情其實很複雜,但卻沒有憤怒,在我腦中揮之不去的卻是 盜火 英雄普羅公尺修斯的偉大形象。想想看,如果不是盜版,作為普通的個人使用者,...