除了%hn%hhn(其中hhh指定pointed-to对象的大小)之外,printf格式说明符的hhh修饰符的意义是什么?

由于标准要求应用于可变函数的默认升级,不可能将类型charshort(或其任何有符号/无符号变体)的参数传递给printf.

根据7.19.6.1(7),h修改量:

以下d、i、o、u、x或x转换规范适用于

如果参数实际上是类型shortunsigned short,那么升级到int,然后再转换回shortunsigned short,将产生与升级到int相同的value,而不进行任何转换.因此,对于类型shortunsigned short的参数,%d%u等应该给出与%hd%hu等相同的结果(对于char类型和hh也一样).

据我所知,hhh修饰符可能有用的唯一情况是参数传递给它的int超出了shortunsigned short的范围,例如

printf("%hu", 0x10000);

但我的理解是,像这样传递错误的类型会导致未定义的行为,因此您不能期望它打印0.

我见过的一个实际 case 是这样的代码:

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

作者期望它打印f0,尽管实现具有签名的纯char类型(在这种情况下,printf("%x", c)将打印fffffff0或类似类型).但是,这样的期望有根据吗?

(注意:实际情况是,原来的类型是char,它被提升为int,然后转换回unsigned char而不是char,从而更改了打印的值.但是该标准是否规定了此行为,或者它是损坏的软件可能依赖的实现细节吗?)

推荐答案

一个可能的原因是:在格式化输入函数中使用这些修饰符是对称的吗?我知道这不是绝对必要的,但也许这是有价值的?

尽管他们没有提到the C99 Rationale document中"h"和"hh"修饰符的对称性的重要性,但委员会确实提到了它作为fscanf()支持"%p"转换说明符的考虑因素(尽管这在C99中并不新鲜-C90中支持"%p"):

C89中添加了带有%p的输入指针转换,尽管这显然有风险,因为它与fprintf对称.

在关于fprintf()的小节中,C99基本原理文档确实讨论了添加了"hh",但只是让读者参考fscanf()小节:

C99中添加了%hh和%ll长度改进剂(见§7.19.6.2).

我知道这是一条细线,但我还是在猜测,所以我想我会给出任何可能的论点.

此外,为了完整起见,"h"修饰符在最初的C89标准中-即使由于现有的广泛使用而不是严格必要的,即使可能没有使用该修饰符的技术要求,它也会存在.

C++相关问答推荐

如何在 C++ 中包含使用 C++ 关键字作为标识符的 C 标头?

如何在 C 中的结构数组中使用动态二维数组?

如何获得 C 函数的基本编译二进制代码?

C 编程语言中有范围运算符吗?

最新 container_of 宏中 __mptr 的用途是什么?

在没有辅助函数的情况下转换函数指针参数

浮点文字中有效十进制数字的最小数量是多少,以尽可能正确地表示该值?

如何仅将 C 中 for 循环中的三个最大整数分配给三个单独的变量?

新手:定义的字符串是否设置为所有 NULL?

打印函数指针时不兼容的指针类型警告

为什么 gcc -march=znver1 限制 uint64_t 向量化?

OpenSSL 3 Diffie-Hellman 密钥交换 C++

char 数组是否保证为空终止?

如果平台上“long”和“int”的大小相同 - “long”和“int”有什么不同吗?

假设指向同一个变量的两个指针是非法的/UB,为什么 C 编译器不能优化更改 const 指针的值?

从函数返回结构时可能出现 GCC 错误

在 C/C++ 中获得正模的最快方法

为什么 C 和 C++ 允许表达式 (int) + 4*5?

如何在 C++ 类内存结构中创建“间隔符”?

为什么首选 uint32_t 而不是 uint_fast32_t?