IT이야기

printf를 통해 보완이 다르게 동작하는 이유는 무엇입니까?

cyworld 2022. 6. 11. 11:49
반응형

printf를 통해 보완이 다르게 동작하는 이유는 무엇입니까?

비트 연산자에 대한 장을 읽다가 우연히 1의 보완 연산자 프로그램을 발견하여 Visual C++에서 실행하기로 했습니다.

int main ()
{
   unsigned char c = 4, d;
   d = ~c;
   printf("%d\n", d);
}

유효한 출력을 얻을 수 있습니다.251

그럼 사용하는 대신d가치를 보유하는 변수로~c, 나는 그 가치를 직접 인쇄하기로 결정했다.~c.

int main ()
{
   unsigned char c=4;
   printf("%d\n", ~c);
}

그것은 결과를 준다.-5.

왜 작동하지 않았을까요?

이 스테이트먼트에서는,

printf("%d",~c);

c로 변환됩니다.int1 앞에 타이핑하다 ~(비트 보완) 연산자가 적용됩니다.그 이유는 정수 프로모션이 있기 때문입니다.정수 프로모션은 오퍼랜드에 호출됩니다.~. 이 경우 의 오브젝트unsigned chartype이 (서명된)로 승격됩니다.int(이후)~연산자 평가)에 의해 사용되는printf함수, 매칭 포함%d포맷 지정자.

디폴트 인수 프로모션이 (와 같이)printf개체는 이미 유형이기 때문에 여기서 역할을 하지 않습니다.int.

한편, 이 코드에서는, 다음과 같습니다.

unsigned char c = 4, d;
d = ~c;
printf("%d", d);

다음의 순서가 실행됩니다.

  • c에 의해 정수 프로모션이 이루어집니다.~(상기와 같은 방법으로)
  • ~crvalue는 (서명 첨부)로 평가됩니다.int값(예:-5)
  • d=~c에서 암묵적으로 변환하다int로.unsigned char,~하듯이d그런 타입이 있어요.라고 생각하시면 됩니다.d = (unsigned char) ~c주의해 주세요.d음수일 수 없습니다(이것은 모든 부호 없는 유형에 대한 일반 규칙입니다).
  • printf("%d", d);디폴트 인수 프로모션을 호출하기 때문에d로 변환됩니다.int(음수가 아닌) 값이 보존됩니다(즉,inttype은 모든 값을 나타낼 수 있습니다.unsigned char를 입력합니다).

1) 다음과 같이 가정한다.int의 모든 값을 나타낼 수 있습니다.unsigned char(아래 T.C.의 코멘트를 참조해 주세요).하지만, 이러한 방법으로 발생할 가능성이 매우 높습니다.좀 더 구체적으로 말하면INT_MAX >= UCHAR_MAX유지. 일반적으로는sizeof(int) > sizeof(unsigned char)홀드 및 바이트는 8비트로 구성됩니다.그렇지 않으면c로 변환될 것이다.unsigned int(C11 하위조항 제6.3.1.1/p2에 따라) 및 형식 지정자 또한 이에 따라 변경해야 한다.%uUB(C11 § 7.21.6.1/p9)를 취득하지 않도록 합니다.

char로 승진하다intprintf수술 전 진술~두 번째 토막입니다.그렇게c,어느 것이

0000 0100 (2's complement)  

(32비트 머신 포함)으로 승격됩니다.

0000 0000 0000 0000 0000 0000 0000 0100 // Say it is x  

그리고 그 비트 단위의 보수는 두 개의 값에서 1을 뺀 값과 같다.~x = −x − 1)

1111 1111 1111 1111 1111 1111 1111 1011  

어느 것이-52의 보어 형식으로 10진수로 표시됩니다.

디폴트 프로모션은char c로.int에서도 행해집니다.

d = ~c;

보형 작업 전에 그러나 결과는 다시 변환됩니다.unsigned char~하듯이d종류unsigned char.

C11: 6.5.16.1 단순한 할당(p2):

간단한 할당(=오른쪽 오퍼랜드의 값이 할당식의 유형으로 변환되어 왼쪽 오퍼랜드에 의해 지정된 객체에 저장되어 있는 값이 대체됩니다.

그리고.

6.5.16 (p3) :

할당식의 유형은 lvalue 변환 후 왼쪽 피연산자의 유형입니다.

코드의 동작을 이해하려면 , 「Integer Promissions라고 불리는 개념을 학습할 필요가 있습니다(이것은, 코드에 암묵적으로 발생하는 것으로, 비트와이즈한 NOT 조작이 행해지기 전에 발생합니다).unsigned char초안에 와 같이 N1570은 다음과 같습니다.

§ 6.5.3.3 단항 연산자

  1. ~operator는 해당 (변환된) 피연산자의 비트 단위 보완 값입니다(즉, 변환된 피연산자의 해당 비트가 설정되지 않은 경우에만 결과의 각 비트가 설정됩니다).정수 프로모션은 오퍼랜드에서 수행되며 결과에는 승격 유형이 있습니다.승격된 유형이 '부호되지 않은 유형'인 경우 표현식은~E는, 그 수 있는 합니다.E

★★★★★★★★★★★★★★★★★★unsigned char이 (바이트 수가 때문에).int - machine에 의해 타입 과 변수 타입의 값, - abstract machine(어드밴스트)에 의해 실행되는 값cint 연산 전)~을 위해서 ~이치노

§ 6.5 표현

  1. 일부 연산자(단항 연산자 및 이진 연산자)<<,>>,&,^ , , , , 입니다.|(일괄적으로 비트 연산자로 기술됨)에는 정수 타입을 가진 오퍼랜드가 필요합니다.이러한 연산자는 정수의 내부 표현에 의존하는 값을 산출하며, 서명된 유형에 대해 구현 배제 및 정의되지 않은 측면이 있다.

컴파일러는 식 분석, 식 의미 검사, 유형 검사 및 산술 변환(필요한 경우)을 수행할 수 있는 스마트한 기능입니다.에 이렇게 해요.~char가 으로 쓸 없는 ~(int)c: 명시적 타입 캐스팅이라고 불립니다(오류를 방지합니다).

주의:

  1. 의 값cint~c단, 의 , 「」, 「」cunsigned char은 아니다 -그것은 아니다.헷갈리지 마세요.

  2. 중요: 결과~은 「」입니다.intgcc를 사용하고 )를 합니다.type! (vs-compiler.gcc가 사용 중입니다.)

    #include<stdio.h>
    #include<stdlib.h>
    int main(void){
       unsigned char c = 4;
       printf(" sizeof(int) = %zu,\n sizeof(unsigned char) = %zu",
                sizeof(int),
                sizeof(unsigned char));
       printf("\n sizeof(~c) = %zu", sizeof(~c));        
       printf("\n");
       return EXIT_SUCCESS;
    }
    

    컴파일하여 다음 작업을 수행합니다.

    $ gcc -std=gnu99 -Wall -pedantic x.c -o x
    $ ./x
    sizeof(int) = 4,
    sizeof(unsigned char) = 1
    sizeof(~c) = 4
    

    주의: 결과 크기~c int ,, to, 일, 일, 습, to, to, to, to, to, to, tounsigned char : ★★★~는 " " 입니다.int! 6.5.3.3 단항 연산자

    1. -operator는 그 (표준) 피연산자의 음수입니다.정수 프로모션은 오퍼랜드에서 수행되며 결과에는 승격 유형이 있습니다.

@hakks 또한 그의 답변에서 설명했듯이 - 그 결과는~c32비트 머신에 탑재되어 있는c = 4다음과 같습니다.

1111 1111 1111 1111 1111 1111 1111 1011

십진법으로 말하면-5두 번째 코드의 출력입니다.

첫 번째 코드에서 한 줄 더 이해하면 재밌을 거예요b = ~c;,왜냐면b는 입니다.unsigned char변수와 결과~c의 것이다int결과 값을 수용하기 위해 입력하다~c로.b결과값(~c)은 다음과 같이 부호 없는 문자 유형에 맞게 잘립니다.

    1111 1111 1111 1111 1111 1111 1111 1011  // -5 & 0xFF
 &  0000 0000 0000 0000 0000 0000 1111 1111  // - one byte      
    -------------------------------------------          
                                  1111 1011  

10진수 등가:1111 1011251. 다음 방법으로 동일한 효과를 얻을 수 있습니다.

printf("\n ~c = %d", ~c  & 0xFF); 

또는 @ouah가 명시적으로 캐스팅을 사용하여 그의 대답에서 제시한 대로.

를 적용할 때~로 교환하다.c로 승격되다int그 결과,int뿐만 아니라.

그리고나서

  • 첫 번째 예에서는 결과가 로 변환됩니다.unsigned char그 후 로 승진했다.signed int인쇄했습니다.
  • 두 번째 예에서는 결과가 다음과 같이 인쇄됩니다.signed int.

작전 5가 나오는데 왜 안 됐나?

대신:

printf("%d",~c);

용도:

printf("%d", (unsigned char) ~c);

첫 번째 예시와 동일한 결과를 얻을 수 있습니다.

~오퍼랜드에는 정수 프로모션이 적용되며 디폴트 인수 프로모션은 가변 함수의 인수에 적용됩니다.

표준에서 정수 프로모션:

부호 있는 정수형을 가진 피연산자의 유형이 부호 없는 정수형을 가진 피연산자 유형의 모든 값을 나타낼 수 있는 경우, 부호 없는 정수형을 가진 피연산자는 부호 있는 정수형을 가진 피연산자의 형식으로 변환되어야 한다.

언급URL : https://stackoverflow.com/questions/28560245/why-does-the-complement-behave-differently-through-printf

반응형