2016-06-02 9 views
1

서명 된 int를 부호없는 int에 할당하려고했습니다.signed int와 unsigned int 사이를 변환하는 동안 형식 변환이 필요합니까?

#include <stdio.h> 

int main() 
{ 
    int a; 
    unsigned int b; 
    scanf("%d", &a); 
    b = a; 
    printf("%d %u\n", a, b); 
    return 0; 
} 

나는이 컴파일하는 것은 내가 부호없는 INT 변수에 int 값을 할당 오전 경고를 일으킬 것이라고 기대했다. 그러나 나는 어떤 경고도 얻지 못했습니다. .

$ gcc -std=c99 -Wall -Wextra -pedantic foo.c 
$ echo -1 | ./a.out 
-1 4294967295 

다음으로 서명 된 int에 부호없는 int를 할당하려고했습니다.

#include <stdio.h> 

int main() 
{ 
    int a; 
    unsigned int b; 
    scanf("%u", &b); 
    a = b; 
    printf("%d %u\n", a, b); 
    return 0; 
} 

경고가 표시되지 않습니다.

$ gcc -std=c99 -Wall -Wextra -pedantic bar.c 
$ echo 4294967295 | ./a.out 
-1 4294967295 

두 질문 :

에는 경고가 입력 가 변환 중에 수정됩니다하더라도 이러한 경우에 생성되지 않습니다 왜
  1. ?
  2. 두 경우 모두 유형 캐스트가 필요합니까?

답변

5

코드 1 :이 변환은 잘 정의되어 있습니다. intunsigned int 범위를 벗어나면 범위를 가져 오려면 UINT_MAX + 1이 추가됩니다.

코드가 정확하고 정상적이므로 경고가 없어야합니다. 그러나 gcc 스위치 -Wconversion을 시도하면 올바른 변환, 특히 부호없는 변환에 대한 경고가 생성됩니다.

코드 2 : 입력이 INT_MAX보다 큰 경우이 변환은 구현 정의입니다. 대부분의 경우 구현은 코드 1의 변환의 반대가되도록 정의합니다.

일반적으로 컴파일러는 해당 구현에서 잘 정의 된 구현 정의 코드에 대해 경고하지 않습니다.다시 -Wconversion을 사용할 수 있습니다.

캐스팅은 필요하지 않으며 일반적인 원칙으로 캐스팅은 오류 메시지를 숨길 수 있으므로 피해야합니다.

+0

나는 마지막 줄에 동의하지 않는다. 캐스트는 자체 문서화 코드로 사용할 수 있습니다. "* 예, 값을 잘라내거나 기호를 변경하지만, 의도적으로 * 수행하고 있습니다." MISRA와 같은 많은 코딩 표준에는 캐스트가 필요합니다. – atturri

+0

@atturri 의견이 맞지 않습니다. 캐스트는 똑같이 잘 나타낼 수 있습니다. "나는 경고를 받았고 사라져 버리고 싶었습니다."- 여러분이 던지더라도 코드는 여전히 도청되었지만 이제는 누군가가'-Wconversion'을 사용하여 잠재적 인 버그를 찾으면 그것을 간과 할 것입니다. 예. MISRA는 끔찍한 IMHO입니다. –

+0

@atturri : 캐스트는 항상 자신이하는 일에 대해 _explicit_하지만 자체적으로 문서화 할 수는 없습니다. 암시 적 변환은 명시 적 변환보다 더 이상의 정보를 잃지 않습니다. –

3

-Wsign-conversion 옵션을 gcc과 함께 사용하면이 경고가 사용됩니다.

-Wsign-conversion
는 부호없는 정수 변수에 부호있는 정수 식을 할당과 같은 정수 값의 부호를 변경할 수 있습니다 암시 적 변환에 대한 경고. 노골적인 던지기가 경고를 침묵시킵니다. C에서이 옵션은 -Wconversion에 의해 활성화됩니다.

4

부호없는 변환은 표준에 의해 잘 정의되어 있으며, 그냥 계산 모듈로 UINT_MAX+1입니다. 따라서 당신은 결코 그것에 대한 경고를 보지 못할 것입니다.

서명되지 않은 부호 변환은 구현에 따라 정의되며 플랫폼에 따라 다릅니다. 이것이 잘못된 것으로 간주 될 때 그리고 때를 보려면 gcc의 문서를 봐야 할 것입니다.

그리고 여기서는 캐스트가 도움이되지 않습니다. 전환의 측면에서 그 결과는 항상 동일 할 것이고, 당신이 달성 할 수 있었던 유일한 것은 경고가 있으면 스위치를 끄는 것입니다. 실제로 C에서 캐스팅이 도움이되는 상황은 거의 없으며 정수에서 정수로의 변환은이 중 결코 불가능합니다.

+0

"서명되지 않은 변환으로 서명했습니다 ... 경고 메시지가 표시되지 않습니다." -> gcc의 -Wconversion이 경고합니다. – chux

0

C89 표준의 저자는 연산의 수치 결과가 INT_MAX + 1u와 UINT_MAX 사이 일지라도 대부분의 당시 컴파일러가 부호가있는 정수와 부호없는 정수를 몇 가지 특수한 경우를 제외하고 동일하게 취급 함을 지적했습니다. 이는 짧은 부호없는 타입이 "unsigned int"가 아닌 "signed int"로 승격되어야한다는 규칙을 이끌어 낸 요인 중 하나입니다. 표준은 이러한 경우 행동을 정의하기위한 구현을 요구하지 않았지만 대부분의 사람들이 그렇게했으며 추세가 지속되지 않을 것이라고 믿을 아무런 이유도없는 것처럼 보였습니다.

불행히도, gcc의 저자는 결과가 INT_MAX 범위에있을 경우 곱하기를 수행하기 전에 부호없는 char에 양수 부호가있는 int를 곱해야하는 코드가 필요하다는 것을 결정했습니다 + 1u ~ UINT_MAX. 하나

unsigned multiply(int x, unsigned char y) { return (unsigned)x*y; } 

보다

unsigned multiply(int x, unsigned char y) { return x*y; } 

오히려 쓰는 경우 컴파일러는 은 일반적으로 최대 UINT_MAX에 대한 모든 결과에 대한 잘 작동 코드를 생성합니다,하지만 때로는 같은 값을 주어 오작동 코드를 생성합니다 .