printf에 대한 h 및 hh 수정 자의 목적은 무엇입니까?
이외에도에서 %hn
와 %hhn
(어디 h
또는 hh
의 지정 크기 뾰족한-에 객체)의 지점 무엇 h
과 hh
에 대한 수정 printf
형식 지정은?
가변 함수에 적용하기 위해 표준에서 요구하는 기본 프로모션으로 인해 유형 char
또는 short
(또는 서명 된 / 부호없는 변형)의 인수 를 printf
.
7.19.6.1 (7)에 따르면 h
수정자는 다음과 같습니다.
다음 d, i, o, u, x 또는 X 변환 지정자가 short int 또는 unsigned short int 인수에 적용되도록 지정합니다 (인수는 정수 승격에 따라 승격되지만 그 값은 short int로 변환됩니다). 또는 인쇄 전 unsigned short int); 또는 다음 n 변환 지정자가 짧은 int 인수에 대한 포인터에 적용됩니다.
인수가 실제로 short
또는 유형 인 경우 unsigned short
, 로의 승격 int
후 다시 로의 변환 short
또는 로의 승격 unsigned short
과 동일한 값이int
다시 변환되지 않은 상태 로 산출 됩니다. 따라서, 유형의 인수 short
또는 unsigned short
, %d
, %u
, 등이 동일한 결과를 수득한다 %hd
, %hu
등 (마찬가지로 대한 char
유형과 hh
).
내가 말할 수있는 한, h
또는 hh
수정자가 유용 할 수있는 유일한 상황 은 인수 int
가 short
또는 범위 밖에서 전달했을 때 입니다 unsigned short
. 예 :
printf("%hu", 0x10000);
그러나 내 이해는 이와 같이 잘못된 유형을 전달하면 어쨌든 정의되지 않은 동작이 발생하므로 0을 인쇄 할 것으로 기대할 수 없습니다.
내가 본 실제 사례 중 하나는 다음과 같은 코드입니다.
char c = 0xf0;
printf("%hhx", c);
서명 f0
된 일반 char
유형 (이 경우 printf("%x", c)
인쇄 fffffff0
또는 유사) 이 있는 구현에도 불구하고 작성자가 인쇄 할 것으로 예상하는 위치 입니다. 그러나 이러한 기대가 정당합니까?
(참고 : 무슨 일이 일어나고 있는지는 원래 유형이 였고 char
, 대신으로 승격되었다가 int
로 다시 변환 되어 인쇄되는 값이 변경됩니다. 의지하고 있습니까?)unsigned char
char
한 가지 가능한 이유 : 형식화 된 입력 함수에서 해당 수정자를 사용하는 대칭 때문입니까? 꼭 필요한 것은 아니지만 그에 대한 가치가 있었을까요?
C99 근거 문서 에서 "h"및 "hh"수정 자에 대한 대칭의 중요성을 언급하지는 않지만 위원회는 "% p"변환 지정자가 지원되는 이유에 대한 고려 사항으로 언급합니다 fscanf()
(그렇지만 C99의 새로운 기능이 아님- "% p"지원은 C90에 있음) :
% p를 사용한 입력 포인터 변환은 fprintf와의 대칭을 위해 분명히 위험하지만 C89에 추가되었습니다.
의 섹션에서 fprintf()
C99 근거 문서는 "hh"가 추가되었음을 설명하지만 독자에게 다음 fscanf()
섹션 을 참조 할뿐입니다 .
% hh 및 % ll 길이 수정자가 C99에 추가되었습니다 (§7.19.6.2 참조).
나는 그것이 미약 한 스레드라는 것을 알고 있지만 어쨌든 추측하고 있으므로 어떤 논쟁이 있을지 모른다고 생각했습니다.
또한 완전성을 위해 "h"수정자는 원래 C89 표준에있었습니다. 수정자를 사용하기위한 기술적 요구 사항이 없더라도 기존에 광범위하게 사용 되었기 때문에 엄격하게 필요하지 않은 경우에도있을 수 있습니다. .
에서 %...x
모드, 모든 값은 부호로 해석됩니다. 따라서 음수는 부호없는 변환으로 인쇄됩니다. 대부분의 프로세서가 사용하는 2의 보수 산술에서는 부호있는 음수와 그에 상응하는 양의 부호없는 등가 사이의 비트 패턴에 차이가 없습니다. 이는 모듈러스 산술로 정의됩니다 (필드의 최대 값 더하기 1을 음수에 더합니다. C99 표준). 많은 소프트웨어 (특히 가장 많이 사용되는 디버깅 코드) %x
는 부호있는 음수 값과 부호없는 캐스트의 비트 표현이 동일하며 2의 보수 시스템에서만 사실이라는 조용한 가정을합니다.
이 캐스트의 메커니즘은 값의 16 진수 표현이 항상 다른 정수 표현이 다른 범위를 갖는 경계 조건에 도달하지 않는 한, 숫자가 2의 보수로 렌더링되었음을 항상 부정확하게 암시합니다. 값 0이 모두 0의 이진 패턴으로 표현되지 않는 산술 표현의 경우에도 마찬가지입니다.
따라서 16 진수 short
로 표시된 네거티브 는 프로모션의 암시 적 기호 확장으로 인해 unsigned long
모든 컴퓨터에서로 채워 지며 인쇄됩니다. 값은 동일하지만, 진정한 단순히 시각적없는 범위의 상당한 양을 의미하는 필드의 크기로 오해한다.f
printf
%hx
실제 사용 사례에서 결론을 내린대로이 패딩을 피하기 위해 표시된 표현을 자릅니다.
의 동작 은으로 인쇄되어야 하는 범위 외부에 printf
전달 될 때 정의되지 않지만, 가장 쉬운 구현은 원시 다운 캐스트에 의해 상위 비트를 버리는 것이므로 사양에는 특정 동작이 필요 하지 않습니다. 정상적인 구현은 잘림을 수행합니다. 하지만 일반적으로 더 나은 방법이 있습니다.int
short
short
printf가 값을 채우지 않거나 부호있는 값의 부호없는 표현을 표시 %h
하지 않으면 그다지 유용하지 않습니다.
내가 생각할 수있는 유일한 용도는 unsigned short
or 를 전달 unsigned char
하고 %x
변환 지정자를 사용하는 것 입니다. 당신은 단순히 베어를 사용할 수 없습니다 %x
- 값으로 승진 할 수있다 int
보다는 unsigned int
, 그리고 당신은 정의되지 않은 동작이있다.
대안은 명시 적으로 인수를 캐스트하는 것입니다 unsigned
. 또는 맨손으로 %hx
/ 를 사용 %hhx
합니다.
printf()
et al에 대한 가변 인수 는 기본 변환을 사용하여 자동으로 승격되므로 short
또는 char
값이 int
함수에 전달 될 때 승격됩니다 .
h
또는 hh
수정자가 없는 경우 올바른 동작을 안정적으로 얻기 위해 전달 된 값을 마스크해야합니다. 수정자를 사용하면 더 이상 값을 마스킹 할 필요가 없습니다. printf()
구현이 제대로 작업을 수행합니다.
특히 형식의 %hx
경우 내부 코드 printf()
는 다음과 같은 작업을 수행 할 수 있습니다.
va_list args;
va_start(args, format);
...
int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!
나는 그것이 short
16 비트 수량 이라고 멍청하게 가정하고있다 . 물론 표준이 실제로 그것을 보장하지는 않습니다.
서명되지 않은 문자를 16 진수로 포맷 할 때 캐스팅을 피하는 것이 유용하다는 것을 알았습니다.
sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));
사소한 코딩 편의성이며 다중 캐스트 (IMO)보다 깨끗해 보입니다.
편리한 또 다른 곳은 snprintf 크기 확인입니다. gcc7은 snprintf를 사용할 때 크기 검사를 추가하여 실패합니다.
char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);
따라서 문자를 포맷 할 때 % d를 사용할 때 더 큰 문자를 사용해야합니다.
here is a commit that shows those fixes instead of increasing the char array size they changed %d to %h. this also give more accurate description
I agree with you that it is not strictly necessary, and so by that reason alone is no good in a C library function :)
It might be "nice" for the symmetry of the different flags, but it is mostly counter-productive because it hides the "conversion to int
" rule.
ReferenceURL : https://stackoverflow.com/questions/4586962/what-is-the-purpose-of-the-h-and-hh-modifiers-for-printf
'programing' 카테고리의 다른 글
단일 어셈블리 다국어 Windows Forms 배포 (ILMerge 및 위성 어셈블리 / 지역화)-가능합니까? (0) | 2021.01.16 |
---|---|
Python 코드를 Arduino (Uno)에 "컴파일"하는 방법이 있습니까? (0) | 2021.01.16 |
클래스 제거시 CSS 애니메이션을 되돌릴 수 있습니까? (0) | 2021.01.16 |
C ++ 모듈을 준비하려면 C ++를 어떻게 작성해야합니까? (0) | 2021.01.16 |
angular2에서 변경 감지를 위해 Observable vs EventEmitter vs Dot Rule을 사용하는 경우 (0) | 2021.01.16 |