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
로 변환됩니다.int
1 앞에 타이핑하다 ~
(비트 보완) 연산자가 적용됩니다.그 이유는 정수 프로모션이 있기 때문입니다.정수 프로모션은 오퍼랜드에 호출됩니다.~
. 이 경우 의 오브젝트unsigned char
type이 (서명된)로 승격됩니다.int
(이후)~
연산자 평가)에 의해 사용되는printf
함수, 매칭 포함%d
포맷 지정자.
디폴트 인수 프로모션이 (와 같이)printf
개체는 이미 유형이기 때문에 여기서 역할을 하지 않습니다.int
.
한편, 이 코드에서는, 다음과 같습니다.
unsigned char c = 4, d;
d = ~c;
printf("%d", d);
다음의 순서가 실행됩니다.
c
에 의해 정수 프로모션이 이루어집니다.~
(상기와 같은 방법으로)~c
rvalue는 (서명 첨부)로 평가됩니다.int
값(예:-5
)d=~c
에서 암묵적으로 변환하다int
로.unsigned char
,~하듯이d
그런 타입이 있어요.라고 생각하시면 됩니다.d = (unsigned char) ~c
주의해 주세요.d
음수일 수 없습니다(이것은 모든 부호 없는 유형에 대한 일반 규칙입니다).printf("%d", d);
디폴트 인수 프로모션을 호출하기 때문에d
로 변환됩니다.int
(음수가 아닌) 값이 보존됩니다(즉,int
type은 모든 값을 나타낼 수 있습니다.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에 따라) 및 형식 지정자 또한 이에 따라 변경해야 한다.%u
UB(C11 § 7.21.6.1/p9)를 취득하지 않도록 합니다.
char
로 승진하다int
에printf
수술 전 진술~
두 번째 토막입니다.그렇게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
어느 것이-5
2의 보어 형식으로 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 단항 연산자
- 의
~
operator는 해당 (변환된) 피연산자의 비트 단위 보완 값입니다(즉, 변환된 피연산자의 해당 비트가 설정되지 않은 경우에만 결과의 각 비트가 설정됩니다).정수 프로모션은 오퍼랜드에서 수행되며 결과에는 승격 유형이 있습니다.승격된 유형이 '부호되지 않은 유형'인 경우 표현식은~E
는, 그 수 있는 합니다.E
★★★★★★★★★★★★★★★★★★unsigned char
이 (바이트 수가 때문에).int
- machine에 의해 타입 과 변수 타입의 값, - abstract machine(어드밴스트)에 의해 실행되는 값c
int
연산 전)~
을 위해서 ~
이치노
§ 6.5 표현
- 일부 연산자(단항 연산자 및 이진 연산자)
<<
,>>
,&
,^
, , , , 입니다.|
(일괄적으로 비트 연산자로 기술됨)에는 정수 타입을 가진 오퍼랜드가 필요합니다.이러한 연산자는 정수의 내부 표현에 의존하는 값을 산출하며, 서명된 유형에 대해 구현 배제 및 정의되지 않은 측면이 있다.
컴파일러는 식 분석, 식 의미 검사, 유형 검사 및 산술 변환(필요한 경우)을 수행할 수 있는 스마트한 기능입니다.에 이렇게 해요.~
char
가 으로 쓸 없는 ~(int)c
: 명시적 타입 캐스팅이라고 불립니다(오류를 방지합니다).
주의:
의 값
c
int
~c
단, 의 , 「」, 「」c
unsigned char
은 아니다 -그것은 아니다.헷갈리지 마세요.중요: 결과
~
은 「」입니다.int
gcc를 사용하고 )를 합니다.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 단항 연산자-
operator는 그 (표준) 피연산자의 음수입니다.정수 프로모션은 오퍼랜드에서 수행되며 결과에는 승격 유형이 있습니다.
@hakks 또한 그의 답변에서 설명했듯이 - 그 결과는~c
32비트 머신에 탑재되어 있는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 1011
이251
. 다음 방법으로 동일한 효과를 얻을 수 있습니다.
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
'IT이야기' 카테고리의 다른 글
vuex 스토어의 개체에서 값 복사본을 반환하려면 어떻게 해야 합니까? (0) | 2022.06.11 |
---|---|
C에 파일이 있는지 확인하는 가장 좋은 방법은 무엇입니까? (0) | 2022.06.11 |
다른 메서드에서 정의된 내부 클래스 내의 비최종 변수를 참조할 수 없습니다. (0) | 2022.06.11 |
char*와 const char*의 차이점 (0) | 2022.06.11 |
스타일링 Vue 슬롯 (0) | 2022.06.11 |