2014-01-06 75 views
4

我運行後續代碼:爲什麼這些變量的地址打印爲ab @和b @?

#include <iostream> 

    using namespace std; 

    typedef struct Test 
    { 
     char a; 
     char b; 
     int i; 
     double d; 
    }Test; 

    int main() 
    { 
     Test test; 
     test.a = 'a'; 
     test.b = 'b'; 
     test.i = 478; 
     test.d = 4.7; 

     cout << &test.a << '\n' 
      << &test.b << '\n' 
      << &test.i << '\n' 
      << &test.d << '\n'; 

     return 0; 
    } 

的輸出是:

[email protected] 
    [email protected] 
    0x28fe94 
    0x28fe98 

首先,我認爲這是&.之間的優先級的結果。
0x28fe940x28fe94表明它不是優先問題。
我可以弄清楚[email protected][email protected]是什麼意思?

回答

5

當你寫

cout << &test.a 

因爲test.achar,這將調用operator<< (ostream&, const char*)過載,以爲你char*是一個指向一個C風格的字符串,而而不僅僅是指向一個字符的指針。因此,該操作將開始讀取從&test.a的內存地址開始的字節,直至找到空終止符(零字節)。出現這種情況打印出來[email protected],因爲a具有價值'a'b具有價值'b',而數字478,您的系統上,恰好對應於一個@角色由空字節最終緊隨其後。

如果你想看到的test.atest.b數字地址,投的指針void* s,這將選擇operator<< (ostream&, const void*)超載。例如:

cout << static_cast<void*>(&test.a) 

希望這有助於!

+0

這很有幫助。謝謝。 – stamaimer

3

這意味着未定義的行爲。 const char *有一個特殊的過載,它將其打印爲空終止的字符串。你們沒有終結者,所以它超越並觸發了上述的UB。有投修復:

std::cout << static_cast<void *>(&test.a) << '\n' 
      << static_cast<void *>(&test.b) << '\n' 
      << &test.i << '\n' 
      << &test.d << '\n'; 
+0

這是真的未定義的行爲,因爲這些字段是給定的數值,還是沒有指定? – templatetypedef

+0

@templatetypedef,好吧,我在Coliru上得到了不同的輸出,所以這裏有一個開始。其他成員可能會發生一些事情,但就我所知,只要他們按照這種順序出現(似乎不包括這種行爲),他們就可以重新排列,因此從技術上來說,這可能是最後一次,到最小的大小,並可能有填充,我不確定是否需要0字節。不妨也提到不可能使用ASCII的可能性,但是你已經知道了。不過,我只是爲了解釋實際發生的事情。 – chris

+0

@templatetypedef:沒有結構打包保證(事實上,不可能考慮到使用的數據類型),因此在假定的ASCIIZ字符串串流期間首次讀取的字段之間可能存在未初始化的內存......不是所有未初始化的讀取有未定義的行爲?我不得不再次檢查標準。如果CPU支持在機器字中寫入特定字節,並且編譯器使用這樣的指令,那麼只有可能咬人,但這不是一個荒謬的假設。 –

1

由於在使用&test.a&test.b時,您傳遞的是字符的地址,因此cout運算符將地址視爲字符串的開頭。這就是爲什麼你先得到[email protected]然後[email protected]@不太明顯;它落在填充值後面的兩個char值和int之前的結構中,並且是準隨機垃圾。你實際上是調用未定義的行爲,因爲你要求輸出代碼訪問填充。如果您想打印地址,請轉至void *。如果您想打印字符,請不要提供地址。

相關問題