C에서 16 진수 문자 인쇄


103

한 줄의 문자를 읽은 다음 해당 문자에 해당하는 16 진수를 인쇄하려고합니다.

예를 들어, "0xc0 0xc0 abc123"처음 두 문자가 c016 진수이고 나머지 문자가 abc123ASCII 인 문자열이 있는 경우 다음을 얻어야합니다.

c0 c0 61 62 63 31 32 33

그러나 printf사용 %x하면

ffffffc0 ffffffc0 61 62 63 31 32 33

없이 원하는 출력을 얻으려면 어떻게합니까 "ffffff"? 그리고 왜 c0 (및 80)에만는 ffffff있지만 다른 문자는없는 이유는 무엇입니까?


바이트 배열과 일치하는 문자열은 다음과 "\xc0\xc0abc123"
같습니다

답변:


132

이 시스템에 서명되어 ffffff있기 때문에 char표시됩니다. C에서와 같은 가변 인자의 기능 printf보다는 모든 정수가 작은 촉진 intint. 이후 char정수 (귀하의 경우 8 비트 부호있는 정수)입니다, 당신의 문자가 승진되는 int부호 확장을 통해.

이후 c080선도적 인 1 비트를 (그리고 8 비트 정수로 음) 샘플에서 다른 사람이하지 않는 동안, 그들은 로그인 확장되고있다.

char    int
c0 -> ffffffc0
80 -> ffffff80
61 -> 00000061

해결책은 다음과 같습니다.

char ch = 0xC0;
printf("%x", ch & 0xff);

이렇게하면 상위 비트는 가려지고 원하는 하위 8 비트 만 유지됩니다.


15
캐스트를 사용하는 내 솔루션 unsigned char은 x86-64 용 gcc4.6에서 하나의 명령어 더 작습니다.
lvella

1
내가 도울 수 있을지도 몰라. 이것은 (기술적으로) 정의되지 않은 동작입니다. 지정자는 x서명되지 않은 유형을 필요로하지만 ch는 int로 승격 되기 때문 입니다. 올바른 코드는 단순히 ch를 unsigned로 캐스트하거나 unsigned char 및 지정자에 캐스트를 사용합니다 : hhx.
2501

1
가있는 경우 printf("%x", 0)아무것도 인쇄되지 않습니다.
Gustavo Meira

최소값이 0으로 설정되어 있기 때문에 아무것도 인쇄하지 않습니다.이 문제를 해결하려면 printf("%.2x", 0);그려지는 최소 문자를 2로 늘려보십시오. 최대 값을 설정하려면. 숫자로. 예를 들어, 당신은 수행하여 그려 단지 2 자 강제 할 수printf("%2.2x", 0);
user2262111

@brutal_lobster의 대답 에서처럼 printf("%x", ch & 0xff)사용 printf("%02hhX", a)하는 것보다 더 나은 이유 는 무엇입니까?
maxschlepzig

62

실제로 int 로의 유형 변환이 있습니다. 또한 % hhx 지정자를 사용하여 유형을 char로 강제 지정할 수 있습니다.

printf("%hhX", a);

대부분의 경우 두 번째 문자를 0으로 채우려면 최소 길이도 설정해야합니다.

printf("%02hhX", a);

ISO / IEC 9899 : 201x는 다음과 같이 말합니다.

7 길이 수정 자와 그 의미는 다음과 같습니다. hh 다음 d, i, o, u, x 또는 X 변환 지정자가 부호있는 문자 또는 부호없는 문자 인수에 적용되도록 지정합니다 (인수는 정수 승격에 따라 승격됩니다. 그러나 그 값은 인쇄하기 전에 부호있는 문자 또는 부호없는 문자로 변환되어야합니다. 또는 다음


30

서명되지 않은 문자를 만들 수 있습니다.

unsigned char c = 0xc5;

이 줄 것이다 인쇄 C5하지 ffffffc5.

127보다 큰 문자 만 ffffff음수이기 때문에 인쇄됩니다 (char는 서명 됨).

또는 char인쇄 하는 동안 캐스팅 할 수 있습니다 .

char c = 0xc5; 
printf("%x", (unsigned char)c);

3
실제 베스트 답변을 +1하고 가능한 한 데이터 선언에 가깝게 명시 적으로 입력합니다 (하지만 더 가깝지는 않음).
Bob Stein

13

char아마도 부호있는 유형 인 변수에 0xc0 값을 저장하고 있으며 값은 음수 (최상위 비트 세트)입니다. 그런 다음 인쇄 할 때로 변환되고 int의미 적 동등성을 유지하기 위해 컴파일러는 추가 바이트를 0xff로 채 웁니다. 따라서 음수 int는 음수 와 동일한 숫자 값을 갖습니다 char. 이 문제를 해결하려면 unsigned char인쇄 할 때 캐스트하십시오 .

printf("%x", (unsigned char)variable);

13

인수가 부호없는 문자임을 hh알리는 데 사용할 수 있습니다 printf. 사용은 0제로 패딩을 얻을 수 및 22로 폭을 설정 x또는 X이하 / 대문자 진수 문자.

uint8_t a = 0x0a;
printf("%02hhX", a); // Prints "0A"
printf("0x%02hhx", a); // Prints "0x0a"

편집 : 독자가 이것이 '올바른'형식 지정자가 아니라는 2501의 주장에 대해 우려한다면 printf링크를 다시 읽으라고 제안 합니다. 구체적으로 특별히:

% c가 int 인수를 예상하더라도 가변 함수가 호출 될 때 발생하는 정수 승격 때문에 char를 전달하는 것이 안전합니다.

고정 너비 문자 유형 (int8_t 등)에 대한 올바른 변환 사양은 헤더 <cinttypes>(C ++) 또는 <inttypes.h>(C)에 정의되어 있습니다 (PRIdMAX, PRIuMAX 등은 % jd, % ju 등과 동의어 임) .

부호있는 대 부호없는 것에 대한 그의 요점은이 경우 값이 항상 양수 여야하고 부호있는 정수에 쉽게 맞아야하므로 중요하지 않습니다. 어쨌든 서명 된 16 진수 형식 지정자는 없습니다.

편집 2 : ( "당신이 틀 렸음을 인정할 때"판) :

311 페이지 (PDF 329) 에서 실제 C11 표준 을 읽으면 다음 을 찾을 수 있습니다.

HH : 지정하는 다음가 d, i, o, u, x, 또는 X변환 지시자는 적용 signed char또는 unsigned char인수 (인수는 정수 프로모션에 따른 증진 된 것이지만, 그 값으로 변환한다 signed char또는 unsigned char인쇄하기 전에); 또는 다음 n변환 지정자가 signed char인수 에 대한 포인터에 적용됩니다 .


uint8_t 유형에 대한 지정자가 올바르지 않습니다. 고정 너비 유형은 특수 인쇄 지정자를 사용합니다. 참조 :inttypes.h
2501

예,하지만 모든 varargs 정수는 암시 적으로 int로 승격됩니다.
Timmmm

그럴 수도 있지만 C가 정의 된 한 올바른 지정자를 사용하지 않으면 동작이 정의되지 않습니다.
2501

그러나 % x 올바른 지정자입니다. ( char및 ) [ en.cppreference.com/w/cpp/language/variadic_arguments]unsigned char 로 승격됩니다 . 당신은 당신의 플랫폼에 맞지 않는 것들에 대한 PRI 지정자 사용해야합니다 예를 - . intintunsigned int
Timmmm

%xint가 아닌 unsigned int에 대해 정확합니다. char 및 unsigned char 유형은 int로 승격됩니다. 또한 uint8_t가 unsigned char로 정의된다는 보장도 없습니다.
2501

2

서명 된 문자 배열에서 인쇄하고있을 것입니다. 부호없는 문자 배열에서 인쇄하거나 0xff로 값을 마스크합니다 : 예 : ar [i] & 0xFF. 높은 (부호) 비트가 설정 되었기 때문에 c0 값이 부호 확장됩니다.


-1

다음과 같이 시도하십시오.

int main()
{
    printf("%x %x %x %x %x %x %x %x\n",
        0xC0, 0xC0, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33);
}

다음을 생성합니다.

$ ./foo 
c0 c0 61 62 63 31 32 33
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.