2014-07-18 39 views
-3

下面的代碼每次輸出不同的數字..
apples.num打印2這是正確的,和蘋果.weight每次打印不同的數字,它曾經甚至打印出「南」,我不'不知道爲什麼會發生這種情況..
真的很奇怪的是,雙(蘋果.volume)打印出2.0 ..

任何人都可以解釋給我的東西嗎?意外的聯盟行爲

#include <stdio.h> 

typedef union { 
    short num; 
    float weight; 
    double volume; 
} Count; 

int main(int argc, char const *argv[]) 
{ 
    Count apples; 
    apples.num = 2; 

    printf("Num: %d\nWeight: %f\nVolume: %f\n", apples.num, apples.weight, apples.volume); 
    return 0; 
} 
+6

不要指望未定義的行爲被定義。 – chris

+0

您只能將該聯合的「short」部分設置爲某個值。其餘的將包含每次重新運行的隨機數據。 – usr2564301

+0

那麼男孩假設要做什麼?只需選擇你蘋果的重量從空氣 –

回答

3

在我看來,你不太明白什麼是工會。一個工會的成員是重疊的價值(換句話說,一個Count工會共享相同的空間三個成員)。

假設,只是爲了示範的目的,一個short是16位(2個字節),一個float爲32位(4個字節)和一個double爲64位(8個字節),則聯合是在8個字節尺寸。在little-endian格式中,num成員表示前2個字節,weight成員表示前4個字節(包括num的2個字節),捲成員表示全部8個字節(包括2個字節的numweight的四個字節)。

最初,你的工會裝着垃圾,即一些未知的位模式,讓我們來顯示它像這樣(十六進制):

GG GG GG GG GG GG GG GG // GG stands for garbage, i.e. unknown bit patterns 

如果設置num爲2,則前兩個字節是0x020x00,但其他字節仍然是垃圾:

02 00 GG GG GG GG GG GG 

如果你讀weight,你只是閱讀的前四個字節,解釋爲float,所以float包含字節

02 00 GG GG 

由於浮點值有完全不同的格式整型像short,你無法預測這些字節(即表示特定的位模式)。它們不代表浮點值2.0f,這可能是你想要的。實際上,一個float的「更顯著」部分存儲在高位字節,即在weight的「垃圾」的一部分,因此它幾乎可以是任何東西,包括一個NaN+infinity-infinity

同樣如果你讀volume,你有一個double一個由字節

02 00 GG GG GG GG GG GG 

的,並且不一定代表2。0(儘管偶然,它可能會非常接近,如果巧合,正確的位被設置在正確的位置,並且如果低位在顯示這樣的值時被捨去)。

聯盟並不意味着要進行從intfloatdouble的適當轉換。他們僅僅意味着能夠爲不同類型的值存儲到同一類型,並從另一成員閱讀爲你設置只是意味着你重新詮釋一些存在於工會的東西完全不同的位。你不是轉換

那麼你如何轉換?這是很簡單的,不需要工會:如果通過「錯誤」的成員訪問聯合(即比它通過指定程序以外的其他成員),結果將依賴於語義

short num = 2; 
float weight = num; // the compiler inserts code that performs a conversion to float 
double volume = num; // the compiler inserts code that performs a conversion to double 
+1

值得注意的是,已設置的位是有效位的最低有效16位。控制你是否有NaN,無窮大,有限大,微小有限,正面,負面等的位仍然是垃圾。 –

+1

我可以做到這一點,但我不確定提及術語「指數」,「有效數」等是不會混淆讀者而不是幫助他。他只需要知道浮點值具有不同的格式。 –

+0

我用我認爲你會理解的術語評論了我的評論。你在用更基本的術語表達信息方面做得很好。同時,有沒有人說過如何正確地將整數值轉換爲相應的float或double值? –

1

您正在訪問未初始化的數據。它將提供未定義的行爲(即:在這種情況下爲未知值)。 You also likely mean to use a struct instead of a union.

#include <stdio.h> 

typedef union { 
    short num; 
    float weight; 
    double volume; 
} Count; 

int main(int argc, char const *argv[]) 
{ 
    Count apples = { 0 }; 
    apples.num = 2; 

    printf("Num: %d\nWeight: %f\nVolume: %f\n", apples.num, apples.weight, apples.volume); 
    return 0; 
} 

由要麼歸零出來,還是最大的成員設置的值初始化工會。即使你設置了最大的成員,其他值也許沒有意義。 This is commonly used for creating a byte/word/nibble/long-word data type and making the individual bits accessible.

+2

平心而論,這仍然不是浮動轉換的* int,因爲OP似乎認爲它是。 – usr2564301

+0

他總是可以做一些像「apples.weight = 1.0f」一樣的東西,並檢查有效性。 – DevNull

+0

清除了一些東西,我認爲工會使用了一些隱式轉換.. –

2

該類型的特定位模式。如果指定的類型具有較小的訪問類型的位寬,則其中一些位將不確定。

+0

我想通了,我必須使用枚舉.. –

+0

@AmrAyman:我不知道你的意思。我懷疑你實際需要的是類型轉換。 – Clifford