標籤:

long Rq = 1432567; int *x; x = (int *)Rq; printf("%d",*x); 錯誤在哪裡?


這段代碼根本就沒有錯誤,謝謝。

所以也不能指望編譯器去檢查一份本來沒有錯誤的代碼中的錯誤。

做底層設備驅動時應當常用類似的代碼。用一個 long 型值保存一個地址,然後強製為一個指針。沒錯,我們常常是真的需要訪問這個地址的數據。

如果一定要說有什麼不妥的地方。指針建議定義為 volatile ,因為基於設備的地址常常在編譯器預料之外的情況下改變,這會影響優化。


long Rq = 1432567;

int *x;

x = (int *)Rq;

printf("%d",*x);

不喜歡看一行這麼多符號,首先將其重排了一下。

要看程序,寫程序,主要是了解其中的邏輯,至於對錯,就在邏輯中間。

這個程序的目的是什麼,單從程序來看,是使用long型定義了一個數Rq,其值為1432567(0x15DBF7)。然後定義了一個int的指針x。

之後,使用強制類型轉換,將Rq轉型為int *,並賦值給x,此時x這個指針的值就是1432567,如果要看x的值,就是1432567;但是x是一個指針,所以它還有一個指向的值,*x也就是1432567這個地址中所存的值,而最後的那個printf是要列印出1432567這個內存地址中所存的值。

所以,這段代碼的邏輯就是上面的,是可以解釋得通的。

那下面我們來看1432567這個地址,對於這個地址,之前回答的兄弟們都寫到了,但是基本上一筆帶過,這裡我稍微多寫一些。因為這個就涉及到開發環境的問題。

我們「正常」認為的開發環境為Windows(這裡討論32位的吧),在這個環境下,操作系統是對內存進行過包裝的,就是所謂的「虛存」,我們程序所在的為一個進程,在32位的環境下,我們的每一個進程都擁有4G的虛存空間,而這4G的虛存空間,又被操作系統(這裡是Windows,每個操作系統可以自己來界定)分為兩個部分,一部分虛存空間被操作系統自己使用,叫做內核空間;另一部分被應用程序(這裡就是我們用VC寫的程序)使用,叫做用戶空間。在32位Windows的情況下,是被分為2G的內核空間和2G的用戶空間的,而用戶空間,又會被分為堆區,棧區等。而VC中所訪問的「內存」,是被操作系統包裝過的虛擬內存,並不是實際的物理內存。

C語言最好的地方就是可以直接和硬體來打交道,但是最靈活,最難掌握的也是這個,指針就是其中最麻煩的部分了。所謂能力越大,責任越大。在語言的層面,我們可以訪問1432567這個內存地址,看其中的內容,但是,不要忘了,我們的環境在進程中,架在操作系統的虛擬內存體系上。這個內存地址是否可以訪問,要操作系統來檢查一下。而1432567這個地址,這裡所以在運行期出現異常,是因為操作系統在檢查之後,不允許你訪問(多謝@梁博文 指正,這裡說法太武斷了,除了內核區域訪問違例外,其他要看具體內存分配)。如果要修正這個錯誤,就要修正你的邏輯,你是要訪問1432567這個值,還是這個內存地址,具體可以參照@陳良喬的答案。

而另外,其實除了Windows之外,還有一片廣大的天空(不要以為Windows就是整個世界哦),這裡的代表就是嵌入式設備,而其中的典型就是無操作系統,直接操作硬體的嵌入式設備。在這裡,是C大展拳腳的機會,我們可以用它看看這裡的寄存器,摸摸那裡的內存,只要你確定你要去「摸」那個內存,這段代碼在運行期也有可能不會出錯,具體就可以參照@pansz的答案。

至於編譯期錯誤和運行期錯誤,我假定你已經理解了,這裡就不多說了,只要記住一個,編譯通過僅僅是一個開始,連成功的一半都不算,而不是已經成功了。

上面寫了一堆,總結一下就是,C語言給了程序員最大的許可權,但是能力和責任是需要匹配的。你如果要訪問內存,你就有責任去了解你要訪問的那個內存,裡面是存放了那些內容,是不是你所需要去訪問的那塊。把握住這個原則,這個問題就不成問題了。


看你希望輸出什麼。

如果你希望輸出「1432567「,參見@陳良喬 的答案。如果你是初學者,那應該是這種情況。

如果你希望輸出內存中1432567地址的數據,參見@pansz 的答案。在這種情況下,此代碼雖然正確,但僅在某些特殊環境下成立(比如搭配固定硬體);若環境配置不對,則「內存訪問異常」是正常的。


錯誤在於預設執行環境的指針變數長度與long相同。嗯,不是嗎?


錯誤在於

x = (int *)Rq

這一句。

你這樣寫,表達的意義是將Rq這個值(1432567)強制類型轉換為一個int*指針

這時,1432567已經不再是一個數據量,而成了一個內存地址

所以,當你後面用printf輸出*x的時候,實際上輸出的是1432567這個內存地址上的數據(任意的不確定的),而不可能是你期望的1432567本身

正確的,應該是取得Rq這個變數的地址賦值給x

x=(int*)Rq;


x = (int *)Rq;


你這個問題問的不對,首先,現代編譯器都有非常友善的錯誤提示,你應該根據錯誤提示去定位問題,錯誤一般都關聯到行號,還有錯誤描述,把錯誤描述輸入GOOGLE,你可以找到99%的答案。

對於運行時的錯誤,流行的開發工具都提供了調試器的功能,通過調試器可以查看出錯時各個變數的狀態,通過這些線索,去找到錯誤的真正原因。

不要看到一大堆英文就選擇性忽略,否則程序之路走不遠,靠肉眼發現問題,永遠沒有工具來的方便。


推薦閱讀:

為什麼說:不要使用 dynamic_cast, 需要運行時確定類型信息, 說明設計有缺陷?
c++函數如何接受數量不定的函數參數?
如何評價使用後綴樹以及CritBitTree壓縮數據的PiXiu方法?
作為一名有女(男)朋友的程序員是一種什麼體驗?
對象沒有默認構造函數,如何定義對象數組?

TAG:C編程語言 | CC |