programing

((무부호 char)0x80) << 24가 0xFFFFFF800000(64비트)로 확장되는 이유는 무엇입니까?

bestprogram 2023. 9. 24. 13:04

((무부호 char)0x80) << 24가 0xFFFFFF800000(64비트)로 확장되는 이유는 무엇입니까?

다음프로그램

#include <inttypes.h> /*  printf(" %" PRIu32 "\n"), my_uint32_t) */
#include <stdio.h> /* printf(), perror() */

int main(int argc, char *argv[])
{
  uint64_t u64 = ((unsigned char)0x80) << 24;
  printf("%"  PRIX64 "\n", u64);

  /* uint64_t */ u64 = ((unsigned int)0x80)  << 24;
  printf("%016"  PRIX64 "\n", u64);
}

생산품

FFFFFFFF80000000
0000000080000000

입니까의 입니까?((unsigned char)0x80)그리고.((unsigned int)0x80)이런 맥락에서?

그런 것 같습니다.(unsigned char)0x80다로 합니다.(unsigned char)0xFFFFFFFFFFFFFF80이만,unsigned char서명이 되어 있습니까?

에 롭습니다.0x80 << 16를 생성합니다.다.0x0000000000800000.

C 컴파일러는 시프트를 실행하기 전에 정수 프로모션을 수행합니다.

표준 규칙 6.3.1.1은 다음과 같이 말합니다.

만약에int 수 됩니다. 값은 다음으로 변환됩니다.int , , 로됩니다 으로 됩니다.unsigned int이런 이라고 합니다 이런 것들을 정수승진이라고 합니다.

이 ㅇunsigned char 수 .int,0x80다로 됩니다.int에 입니다.unsigned int 중 를 는 a 로할 수 .int, 그래서 남아있습니다.unsigned int정수 승진을 한 다음에.

의 입니다.<<연산자는 정수 승격을 거칩니다.

(C99, 6.5.7p3) "각 피연산자에 대해 정수 승격을 수행합니다."

이 뜻은 다음과 같습니다.

 ((unsigned char)0x80) << 24

는 다음과 같습니다.

 ((int) (unsigned char)0x80) << 24

다음에 해당하는:

  0x80 << 24

의 사인 하는 것입니다.intint시스템.그럼 언제0x80 << 24다로 됩니다.uint64_tu64을 산출하기 위해 합니다.0xFFFFFFFF80000000.

편집:

Matt McNabb이 정확하게 코멘트에 덧붙인 것처럼, 기술적으로0x80 << 24가 C에서할 수 되지 않은 을 호출합니다. 결과가 의 유형에서 표현할 수 없기 때문입니다.<<왼쪽 피연산자사용하시는 경우gcc, 현재 컴파일러 버전은 현재 이 작업을 정의되지 않은 상태로 만들지 않는다는 것을 보장합니다.

은 를 변환할 때 합니다.<<int32터에서 unt64지까지.당신은 32비트 시스템에서 작업 중이므로 정수 타입의 크기는 32비트입니다.다음 코드:

 u64 = ((int) 0x80) << 24;
 printf("%llx\n", u64);

인쇄:

 FFFFFFFF80000000

는 을 주기 때문입니다 (0x80 << 24)0x80000002147483648의 32입니다의 입니다.는 부호 여 64합니다를 합니다.0xFFFFFFFF80000000.

당신이 목격하고 있는 것은 명확하지 않은 행동입니다.C99 §6.5.7/4는 다음과 같이 좌측 이동을 설명합니다.

의 .E1 << E2이다.E1E2비트 위치; 빈 비트는 0으로 채워집니다. 만약E1 없는 을 가지며,다입니다. 결과 값은E1× 2E2, 모듈로를 결과 유형에서 나타낼 수 있는 최대값보다 하나 더 감소시킨 경우,E1는 및이 아닌 다.E1× 2는E2 결과 유형으로 나타낼 수 있으며, 결과 값입니다. 그렇지 않으면 동작이 정의되지 않습니다.

당신 같은 경우엔E1128의 값을 가지며, 그 종류는int,것은 아니다.unsigned char. 다른 답변들이 언급한 바와 같이, 가치는 다음으로 승격됩니다.int평가전에관련 피연산자들이 서명되어 있습니다.int 으로 24 은 2147483648 로, 보다 1 로 보다 한 개 더 .int시스템 상에서.따라서 프로그램의 동작은 정의되지 않습니다.

이것을 피하기 위해, 당신은 다음의 유형을 확인할 수 있습니다.E1이다.unsigned int서 대신 unsigned char.

C 표준의 진화에 있어서 한 가지 주요한 어려움은 언어를 표준화하려는 노력이 이루어졌을 때, 특정한 것들을 서로 다르게 하는 구현들이 있었을 뿐만 아니라, 그러한 행동의 차이에 의존하는 구현들을 위해 작성된 상당한 코드들이 있다는 것입니다.C 표준을 만든 사람들은 구현이 사용자가 의존할 수 있는 방식으로 실행되는 것을 금지하는 것을 피하기 원했기 때문에, C 표준의 특정 부분은 정말 엉망입니다.최악의 측면 중 일부는 당신이 관찰한 것과 같은 정수 승진의 측면에 관한 것입니다.

으로, 를 이 더 일 것 .unsigned char다로 .unsigned intsigned int 의 에 다른 때.-교환입니다. 하면 큰 얻을 수 다른 연산자를 조합하면 큰 결과를 얻을 수 있지만 다른 연산자가 아닌 다른 연산자는 없습니다 이외에는 다른 -부정적인 결과를 가져올 수 있습니다.이유를 알아보기 위해signed int결과가 부정적일 수 없음에도 불구하고 다음을 고려하여 선택했습니다.

int i1; unsigned char b1,b2; unsigned int u1; long l1,l2,l3;

l1 = i1+u1;
l2 = i1+b1;
l3 = i1+(b1+b2);

에는 두 의 다른 의 연산이 유형을 할 수 메커니즘이 첫 문장은 또는 서명되지 않은 대로 되지 않은 경우 덜 수 있습니다 C 는 , 수행해야 합니다; 서명되지 않은 것은 일반적으로 약간 덜 놀라운 결과를 산출합니다.특히 정수 리터럴은 기본적으로 서명되어 있기 때문에 (추가한다면 매우 이상할 것입니다.11u부호가 없는 값으로 하면 음이 될 수 있습니다.세 입니다의 수 입니다.i1큰 수의 부호가 없는 숫자 의 첫 되지 않은 하지만 세 위의 첫번째 문장은 서명되지 않은 결과를 얻지만 세번째 문장은 서명된 결과를 얻는다는 것은 다음을 의미합니다를 의미합니다.(b1+b2)서명해야 합니다.

IMHO에서 서명 관련 문제를 해결하는 "올바른" 방법은 "포장" 동작을 문서화한 별도의 숫자 유형을 정의하는 것입니다(기존의 서명되지 않은 유형이 정의하는 것과 같이). 그리고 정수와 같이 동작해야 하며 두 유형이 서로 다른 승격 규칙을 나타내도록 하는 것입니다.구현은 기존 유형을 사용하는 코드에 대해 기존 동작을 계속 지원해야 하지만, 새로운 유형은 호환성보다 사용성을 선호하도록 설계된 규칙을 구현할 수 있습니다.

언급URL : https://stackoverflow.com/questions/29538935/why-does-unsigned-char0x80-24-get-sign-extended-to-0xffffffff80000000-64