Aside from %hn and %hhn (where the h or hh specifies the size of the pointed-to object), what is the point of the h and hh modifiers for printf format specifiers?

Due to default promotions which are required by the standard to be applied for variadic functions, it is impossible to pass arguments of type char or short (or any signed/unsigned variants thereof) to printf.

According to 7.19.6.1(7), the h modifier:

Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing); or that a following n conversion specifier applies to a pointer to a short int argument.

If the argument was actually of type short or unsigned short, then promotion to int followed by a conversion back to short or unsigned short will yield the same value as promotion to int without any conversion back. Thus, for arguments of type short or unsigned short, %d, %u, etc. should give identical results to %hd, %hu, etc. (and likewise for char types and hh).

As far as I can tell, the only situation where the h or hh modifier could possibly be useful is when the argument passed it an int outside the range of short or unsigned short, e.g.

printf("%hu", 0x10000);

but my understanding is that passing the wrong type like this results in undefined behavior anyway, so that you could not expect it to print 0.

One real world case I've seen is code like this:

char c = 0xf0;
printf("%hhx", c);

where the author expects it to print f0 despite the implementation having a plain char type that's signed (in which case, printf("%x", c) would print fffffff0 or similar). But is this expectation warranted?

(Note: What's going on is that the original type was char, which gets promoted to int and converted back to unsigned char instead of char, thus changing the value that gets printed. But does the standard specify this behavior, or is it an implementation detail that broken software might be relying on?)

推荐答案

One possible reason: for symmetry with the use of those modifiers in the formatted input functions? I know it wouldn't be strictly necessary, but maybe there was value seen for that?

Although they don't mention the importance of symmetry for the "h" and "hh" modifiers in the C99 Rationale document, the committee does mention it as a consideration for why the "%p" conversion specifier is supported for fscanf() (even though that wasn't new for C99 - "%p" support is in C90):

Input pointer conversion with %p was added to C89, although it is obviously risky, for symmetry with fprintf.

In the section on fprintf(), the C99 rationale document does discuss that "hh" was added, but merely refers the reader to the fscanf() section:

The %hh and %ll length modifiers were added in C99 (see §7.19.6.2).

I know it's a tenuous thread, but I'm speculating anyway, so I figured I'd give whatever argument there might be.

Also, for completeness, the "h" modifier was in the original C89 standard - presumably it would be there even if it wasn't strictly necessary because of widespread existing use, even if there might not have been a technical requirement to use the modifier.

C++相关问答推荐

为什么信号量为空= 0,而不是阻塞?

通过MQTT/蚊子发送大文件—限制在4MB

C指针算法在函数参数中的应用

为什么在4.9.37版的内核中,kfio还需要smp_wmb呢?

堆栈在作用域阻塞后会被释放吗?

将指针作为参数传递给函数

将fget()与strcMP()一起使用不是正确的比较

如何将长字符串转换为较小的缩写,该缩写由第一个字符、最后一个字符和中间的字符数组成?

自定义变参数函数的C预处置宏和警告 suppress ?

将数据移动到寄存器时出现分段故障

试图创建一个基本的Word克隆,但遇到了障碍

Valgrind正在使用一个Fexecve电话报告不可能发生的事情

如何打印循环调度问题的时间表

execve 不给出which命令的输出

使用 _Atomic float 时,MSVC 编译的代码会命中调试断言

C Makefile - 如何避免重复提及文件名

在C中定义函数指针?

GDB 用内容初始化数组

C11 嵌套泛型

如何在 C 中编辑 struct 体中的多个变量