2011-11-12 52 views
6

今天我有一個奇怪的問題。C++聯合來表示數據內存vs C標量變量類型

的代碼(C++)

#include <iostream> 

union name 
{ 
    int num; 
    float num2; 

}oblong; 


int main(void) 
{ 
    oblong.num2 = 27.881; 

    std::cout << oblong.num << std::endl; 

    return 0; 
} 

的代碼(C)

#include <stdio.h> 

int main(void) 
{ 
    float num = 27.881; 

    printf("%d\n" , num); 

    return 0; 
} 

問題

  1. 我們知道,C++工會可以HOL d多於一種類型的數據元素,但一次只有一種類型。所以基本上name oblong只會保留32位內存的一部分(因爲union中的最大類型是32位,int和float),並且這部分可以保存一個整數或浮點數。

  2. 所以我只是分配一個值爲27.881到oblong.num2(正如你可以看到上面的代碼)。但出於好奇,我使用oblong.num訪問內存指向相同的內存位置。

  3. 正如預期的那樣,它給了我一個值不是27,因爲浮點和整數的方式記憶裏表示是不同的,這就是爲什麼當我使用oblong.num訪問內存部分,它會處理內存值的那部分作爲整數並使用整數表示方式來解釋它。

  4. 我知道這個現象也將用C發生,這就是爲什麼我初始化一個浮點類型變量和值,並在以後使用%d。所以在讀它,我只是嘗試一下使用相同的值27.881,你可以往上看。但是當我運行它時,發生了一些奇怪的事情,那就是我在C中獲得的價值與C++不同。

  5. 這是爲什麼發生?從我所知道的最後兩個代碼中得到的兩個值不是垃圾值,但爲什麼我會得到不同的值?我還使用sizeof來驗證C和C++整數和浮點大小,並且都是32位。所以內存大小不是導致這種情況發生的原因,那麼是什麼促成了這種差異呢?

+1

相同案例:http://stackoverflow.com/questions/2377733/how-does-this-program-work 這也是:http://stackoverflow.com/questions/2398791/how-is-conversion- of-float-double-to-int-handling-in-printf –

+0

區別不在於C與C++。您也可以在C++中編譯第二個示例,並從C和C++獲取相同的結果。第一個使用'union'的例子需要一點點改動來使用'printf',而不是'std :: cout <<',但是之後你會再次得到來自C和C++的相同結果。 – MSalters

回答

9

首先,錯誤的printf()格式字符串是未定義的行爲。現在,說,這裏是什麼,是你的情況實際發生的情況:

在可變參數的功能,例如printf(),比int較小的整數提升爲int和彩車比double小被晉升爲double

結果是您的27.881正在轉換爲8字節雙精度值,因爲它被傳遞到printf()。因此,二進制表示不再與float相同。

格式字符串%d需要一個4字節的整數。所以實際上,您將打印27.881的雙精度表示的較低4字節。(假設小端)

*其實(假設嚴格-FP),你看到的27.881底部的4個字節它轉換爲float後,再晉升爲double

2

在這兩種情況下,您遇到未定義的行爲。你的實現只是做了一些奇怪的事情。

+0

兩種情況?我認爲只有第二個printf是未定義的。第一個是一個轉儲,它有一個從float中提供的明確的bitpattern。 (當然是另一個問題) – Bort

+0

第一種情況是UB,因爲你通過類型爲'int'的表達式訪問對象'float(27.881)'。對象必須通過它們自己的類型的表達式來訪問,或者通過(無符號)'char []'來訪問。後者的規則是你可以使用'memcpy'對象(在C中; C++將'memcpy'限制爲普通的舊數據)。 – MSalters