programing

형식 변환 - 서명된 int/char로 서명되지 않음

bestcode 2022. 8. 31. 22:44
반응형

형식 변환 - 서명된 int/char로 서명되지 않음

아래 프로그램을 실행하려고 했습니다.

#include <stdio.h>

int main() {
    signed char a = -5;
    unsigned char b = -5;
    int c = -5;
    unsigned int d = -5;

    if (a == b)
        printf("\r\n char is SAME!!!");
    else
        printf("\r\n char is DIFF!!!");

    if (c == d)
        printf("\r\n int is SAME!!!");
    else
        printf("\r\n int is DIFF!!!");

    return 0;
}

이 프로그램의 출력은 다음과 같습니다.

char is DIFF!!!int는 똑같아!!!

왜 양쪽에서 다른 출력을 얻을 수 있을까요?
력음음음 음음음?

char는 똑같아!!!int는 똑같아!!!

코드패드 링크

이는 C의 다양한 암묵적 유형 변환 규칙이 있기 때문입니다.C 프로그래머가 알아야 할 두 가지가 있습니다: 일반적인 산술 변환정수 승수(후자는 전자의 일부입니다).

char라는 .(signed char) == (unsigned char)작은 정수형입니다.기타 작은 정수형은 다음과 같습니다.bool ★★★★★★★★★★★★★★★★★」short. 정수 승격 규칙에는 작은 정수 유형이 작업의 피연산자일 때마다 해당 유형이 다음과 같이 승격된다고 명시되어 있습니다.int서명되어 있습니다.이 문제는 유형이 서명되었는지 여부에 관계없이 발생합니다.

signed char 사인은 되고, 이 은 '아까', '아까', '아까', '아까보다'로int199 -5면 되다.unsigned char251(0xFB)로 설정하다to로 an an an an 됩니다.int이치노결 you.........

if( (int)-5 == (int)251 )

정수 케이스에는 다음과 같은 유형이 있습니다.(signed int) == (unsigned int). 이들은 작은 정수형이 아니므로 정수 프로모션은 적용되지 않습니다.대신, 두 오퍼랜드가 같은 "랭크"(크기)를 가지지만 다른 시그니처를 가지면 서명된 오퍼랜드가 서명되지 않은 오퍼랜드와 동일한 타입으로 변환된다는 일반적인 산술 변환에 의해 균형이 유지됩니다.결국엔...

if( (unsigned int)-5 == (unsigned int)-5)

'16'의 -5 말합니다

  • complete 8µs, 2's completive 2µssigned char0xfb
  • 의 보완 , 2의 보완 32비트, 2의 보완 2비트signed int0xfffffffb

부호 있는 숫자를 부호 없는 숫자로 변환하거나 그 반대로 변환하면 컴파일러는 다음을 수행합니다.정확히 아무것도 아니야.어떻게 해야 하죠?이 숫자는 변환 가능하거나 변환 불가능하며, 이 경우 정의되지 않은 동작 또는 구현 정의 동작이 뒤따릅니다(실제로 어떤 동작을 확인하지는 않았습니다). 가장 효율적인 구현 정의 동작은 아무것도 하지 않는 것입니다.

은 16진수 표현입니다.(unsigned <type>)-5 말합니다

  • 8기가비트,unsigned char0xfb
  • 32기가비트,unsigned int0xfffffffb

낯이 익어요?서명된 버전과 완전히 일치합니다.

쓸 때if (a == b)서, snowledge.a ★★★★★★★★★★★★★★★★★」b are 입니다.char 할 은 '읽다'입니다if ((int)a == (int)b)(이것이 바로 모두가 떠드는 정수 프로모션입니다.)

이렇게 요?char로로 합니다.int

  • 비트 8 기가비트signed char 32인치로signed int0xfb->0xfffffffb
    • 그건 이 되네. 왜냐하면 은 ,, 건의 과 이야.-5 위! 위! 위! 위!
    • 바이트의 상위 비트인 "사인 비트"를 왼쪽으로 복사하여 "사인 확장"이라고 합니다.
  • 비트 8 기가비트unsigned char 32인치로signed int0xfb->0x000000fb
    • 이번에는 source type이 서명되지 않았기 때문에 복사할 부호 비트가 없기 때문에 "제로 확장"이 수행됩니다.

so,는,a == b 그렇다0xfffffffb == 0x000000fb=> 치없!!!

ㅇㅇㅇㅇㅇ.c == d 그렇다0xfffffffb == 0xfffffffb=> 일!!

정수 프로모션에 오신 것을 환영합니다.웹사이트에서 인용하자면:

int가 원래 유형의 모든 값을 나타낼 수 있는 경우 값은 int로 변환됩니다.그렇지 않은 경우 부호 없는 int로 변환됩니다.이를 정수 프로모션이라고 합니다.다른 모든 유형은 정수 프로모션에 의해 변경되지 않습니다.

C는 이러한 비교를 할 때 매우 혼란스러울 수 있습니다.저는 최근에 C가 아닌 몇몇 프로그래밍 친구들을 다음과 같은 놀림으로 곤혹스럽게 했습니다.

#include <stdio.h>
#include <string.h>

int main()
{
    char* string = "One looooooooooong string";

    printf("%d\n", strlen(string));

    if (strlen(string) < -1) printf("This cannot be happening :(");

    return 0;
}

인쇄가 것은 「 」입니다.This cannot be happening :(알 수 있습니다! 25는 -1보다 작습니다!

단, 그 아래에서는 -1이 부호 없는 정수로 표시되며, 32비트시스템에서는 기본 비트 표현에 의해 4294967295와 동일합니다.그리고 25는 4294967295보다 작습니다.

, 을 했을 size_tstrlen부호 있는 정수로 지정합니다.

if ((int)(strlen(string)) < -1)

그러면 25와 -1을 비교해서 모든 것이 세계와 잘 될 것이다.

좋은 컴파일러는 부호 없는 정수와 부호 있는 정수의 비교에 대해 경고해야 하지만 여전히 놓치기 쉽습니다(특히 경고를 활성화하지 않은 경우).

이것은 Java 프로그래머에게 특히 혼란스러운 일입니다. 왜냐하면 모든 원시적인 타입이 서명되어 있기 때문입니다.James Gosling(Java의 창시자 중 한 명)은 이 주제에 대해 다음과 같이 말했다.

고슬링:언어디자이너로서 지금은 별로 생각하지 않지만, J.Random Developer가 그 스펙을 머릿속에 담아둘 수 있을 것 같은 '단순함'이 되어 버린 것입니다.이 정의에서는 Java는 그렇지 않습니다.예를 들어, 많은 언어들은 결국 아무도 이해하지 못하는 많은 궁지에 몰리게 됩니다.C 개발자에게 서명되지 않은 것에 대해 질문해 보면, 거의 모든 C 개발자가 실제로 서명되지 않은 산술이 무엇인지 이해하지 못한다는 것을 알 수 있습니다.그런 것들이 C를 복잡하게 만들었다.자바의 언어 부분은 매우 간단하다고 생각합니다.당신이 찾아봐야 할 도서관들.

멋진 질문입니다!

int비교는 기능합니다.이것은, 양쪽의 int가 완전하게 같은 비트를 포함하고 있기 때문에, 기본적으로 같은 비트를 가지고 있기 때문입니다.하지만 이 경우,chars?

아, C는 암묵적으로 홍보한다.char~에 대해서int는 다양한 경우에 사용됩니다.이게 그 중 하나예요.코드상으로는if(a==b)그러나 컴파일러가 실제로 설정하는 것은 다음과 같습니다.

if((int)a==(int)b) 

(int)a-5이지만(int)b251 입니다.그것들은 확실히 같지 않다.

편집: @Carbonic-Acid가 지적했듯이(int)b인 경우에만 이 됩니다.char8시 정각입니다. ifint 길이는 32비트입니다.(int)b32764면 된다.

REDIT: 한 바이트의 길이가 8비트가 아닐 경우 답변의 본질에 대해 많은 코멘트가 있습니다.의 유일한 은 '다르다'라는 것이다.(int)b251이 아니라 -5가 아닌 다른 양수입니다.이것은 여전히 매우 쿨한 질문과는 정말로 관련이 없다.

제 요점은 컴파일 시 "서명된 식과 서명되지 않은 식 비교" 경고를 받지 않았습니까?

컴파일러는 자신에게 이상한 일을 할 권리가 있다는 것을 알려주고 있습니다.:) 덧붙이자면, 원시 타입의 용량에 가까운 큰 값을 사용하면 이상한 일이 일어납니다.그리고.

 unsigned int d = -5;

d에 확실히 큰 값을 할당하고 있습니다.이것은 동등하다고 보증되지 않는 경우라도, 다음과 같습니다.

 unsigned int d = UINT_MAX -4; ///Since -1 is UINT_MAX

편집:

그러나 두 번째 비교만 경고를 주는 것은 흥미롭다(코드 확인).즉, 변환 규칙을 적용하는 컴파일러는 이 두 가지 컴파일러 간의 비교에서 오류가 발생하지 않을 것으로 확신하고 있습니다.unsigned char ★★★★★★★★★★★★★★★★★」char(비교 중에 가능한 모든 값을 안전하게 나타낼 수 있는 유형으로 변환됩니다).그리고 그는 이 점에서 옳다.이 않을 거라고 요.unsigned int ★★★★★★★★★★★★★★★★★」int 중 가 완전히 수 비교 중에 2개 중 하나가 완전히 나타낼 수 없는 유형으로 변환됩니다.

완전성을 위해 짧게 체크했습니다.컴파일러는 chars와 동일하게 동작하며 예상대로 실행 시 에러는 발생하지 않습니다.

.

이 토픽에 관해서, 최근 이 질문을 했습니다(아직은 C++ 지향입니다).

언급URL : https://stackoverflow.com/questions/17312545/type-conversion-unsigned-to-signed-int-char

반응형