2014-07-18 3 views
-3

아래 코드는 매번 다른 숫자를 출력합니다.
apples.num 2는 정확한 값이고 apples.weight는 매번 다른 숫자를 인쇄하고 한 번 "nan"을 출력합니다. 왜 이런 일이 일어나는 지 알지 ..
정말 이상한 점은 double (apples.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 노조 의 세 멤버는 동일한 공간을 공유합니다.

단지 데모를 위해, 가정은 shortfloat 32 비트 (4 바이트), 16 비트 (2 바이트) 및 double 64 비트 (8 바이트), 그 조합은 8 바이트이다 크기. 리틀 엔디안 형식에서는 num 구성원이 처음 2 바이트를 참조하고, weight 구성원은 처음 4 바이트 (num의 2 바이트 포함)를 참조하며 볼륨 구성원은 전체 8 바이트를 나타냅니다 (num의 2 바이트 포함). weight의 네 바이트).

는 처음에는 노동 조합이 쓰레기를 포함, 알 수없는 비트 패턴, 즉의이 (16 진수로)이처럼 표시 할 수 :

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

당신이 num에 2를 설정하면, 처음 두 바이트, 0x020x00 있습니다 그러나 다른 바이트는 여전히 쓰레기입니다 : 당신이 weight을 읽는다면, 당신은 단순히 float으로 해석 처음 4 바이트를 읽기 때문에된다

02 00 GG GG GG GG GG GG 

438,당신이 무엇을 그 바이트를 예측할 수는 소수점 값이 short 같은 필수 유형과 같은 완전히 다른 형식이 부동 때문에 바이트

02 00 GG GG 

을 포함 (즉, 그 특정 비트 패턴)이 나타납니다. 그들은 부동 소수점 값 2.0f를 나타내지 않으므로 아마도 원하는 것입니다. 그것은 NaN, +infinity, -infinity 포함, 거의 모든 것을 할 수 있도록 실제로하는 float의 "더 중요한"부분은 마찬가지로 등, weight의 "쓰레기"일부 즉, 상위 바이트

를 저장 당신이 volume를 읽는다면, 당신은 바이트

02 00 GG GG GG GG GG GG 

로 구성 double을하고 반드시 2를 나타내지 않습니다.0 일 수도 있지만 우연히 올바른 비트가 올바른 위치에 설정되고 그러한 값을 표시 할 때 작은 비트가 반올림되는 경우 우연히 매우 가까이에 올 수 있습니다.

유니온은 int에서 float 또는 double으로의 변환을 의미하지 않습니다. 그것들은 같은 종류의 다른 값을 저장할 수있는 것일 뿐이며, 에서 또 다른 멤버를 읽는 것은 단순히 유니온에 완전히 다른 것으로 표시된 비트 수를 다시 해석한다는 것을 의미합니다. 당신은 이 아니며을 변환합니다.

어떻게 변환하나요? 그것은 매우 간단하고 노동 조합이 필요하지 않습니다 당신이 (즉,이를 통해 할당 된 이외의 멤버), 결과는 의미에 따라 달라집니다 "잘못된"회원을 통해 노조에 액세스하는 경우

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, Infinity, 큰 유한, 작은 유한, 양수, 음수 등을 제어하는 ​​비트는 가비지로 남습니다. –

+1

그럴 수는 있겠지만,'지수 ','significand' 등의 용어를 언급하는 것이 독자의 도움보다 혼란스럽지는 않을지 확신 할 수 없습니다. 그는 단지 부동 소수점 값이 다른 형식을 가지고 있다는 것을 알아야합니다. –

+0

나는 당신이 이해할 것이라고 생각하는 관점에서 내 의견을 표현했습니다. 당신은보다 기본적인 용어로 정보를 표현하는 훌륭한 일을하고 있습니다. 한편, 실제로 정수 값을 해당 float 또는 double 값으로 올바르게 변환하는 방법을 실제로 말한 사람이 있습니까? –

1

초기화되지 않은 데이터에 액세스하고 있습니다. 정의되지 않은 동작을 제공합니다 (이 경우 알 수없는 값).

#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; 
} 

You also likely mean to use a struct instead of a union. 그것을 밖으로 제로, 또는 값으로 가장 큰 멤버를 설정 중 한 가지 방법으로 노조를 초기화합니다. 가장 큰 멤버를 설정하더라도 다른 값은 의미가 없을 수도 있습니다. This is commonly used for creating a byte/word/nibble/long-word data type and making the individual bits accessible.

+2

공평히 말하자면, 이것은 OP가 생각하는 것 같기 때문에 여전히 * 부동 소수점 변환 *이 아닙니다. – usr2564301

+0

그는 언제나'apples.weight = 1.0f'와 같은 것을 할 수 있고 유효성을 검사 할 수 있습니다. – DevNull

+0

그 일을 지우고, 노동 조합은 몇 가지 암시 적 변환을 사용한다고 생각했습니다. –

2

을 그 타입의 특정 비트 패턴 할당 된 타입이 접근 한 비트 폭이 더 작은 경우, 그 비트 중 일부는 정의되지 않습니다.

+0

나는 열거 형을 사용해야 함을 알았습니다. –

+0

@AmrAyman : 무슨 뜻인지 모르겠습니다. 당신이 실제로 필요로하는 것은 타입 캐스트라고 생각합니다. – Clifford