gpt4 book ai didi

c - 1 字节有符号数的 printf 格式

转载 作者:太空狗 更新时间:2023-10-29 17:02:57 24 4
gpt4 key购买 nike

假设如下:

sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
printf 2 字节有符号数的格式为 %hd , 对于 4 字节有符号数是 %d , 对于 8 字节有符号数是 %ld ,但是 1 字节有符号数的正确格式是什么?

最佳答案

what is the correct format for a 1 byte signed number?

%hh 和您选择的整数转换说明符(例如, %02hhX 。请参阅 C11 标准第 7.21.6.1p5 节:

hh

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


括号中的注释很重要。由于对可变参数函数的参数进行整数提升(例如 printf ),该函数永远不会看到 char 参数。许多程序员认为这意味着没有必要使用 hhh 限定符。当然,您不会通过将它们排除在外而创建未定义的行为,而且大多数情况下它会起作用。
但是, char 可能是有符号的,整数提升将保留其值,这将使其成为有符号整数。使用无符号格式(例如 %02X )打印有符号整数将为您提供符号扩展的 F s。因此,如果要使用无符号格式显示有符号 char,则需要使用 printf 告诉 hh 整数类型的原始未提升宽度是多少。
如果不清楚,一个简单的例子(但有争议的)例子:
/* Read the comments thread to this post; I'll remove
this note when I edit the outcome of the discussion into
the answer
*/

#include <stdio.h>
int main(void) {
char* s = "\u00d1"; /* Ñ */
for (char* p = s; *p; ++p) printf("%02X (%02hhX)\n", *p, *p);
return 0;
}
输出:
$ ./a.out
FFFFFFC3 (C3)
FFFFFF91 (91)

在评论线程中,关于上述代码段是否为未定义行为存在(或可能曾经)大量讨论,因为 X 格式规范需要一个无符号参数,而 char 参数是(至少在产生所呈现输出的实现上)有符号.我认为这个论点依赖于 §7.12.6.1/p9:“如果任何参数不是相应转换规范的正确类型,则行为未定义。”
但是,在 char(和 short)整数类型的情况下,参数列表中的表达式在调用函数之前被提升为 intunsigned int。 (值得注意的是,在大多数架构上,所有三种字符类型都将提升为有符号 int ;将 unsigned char(或无符号 char )提升为 unsigned int 只会发生在 sizeof(int) == 1 的实现中,其中 0791045)
因此,在大多数体系结构上, %hx%hhx 格式转换的参数将被签名,如果不使这些格式代码的使用变得毫无意义,就不能是未定义的行为。
此外,标准并没有说 fprintf(和 friend )会以某种方式恢复原始表达式。它所说的是该值“应在打印前将 转换为 有符号字符或无符号字符”(第 7.21.6.1/p5 节,上面引用,强调添加)。
将有符号值转换为无符号值并非未定义。它甚至不是未指定的或依赖于实现的。它简单地由(概念上)“重复地增加或减去比新类型可以表示的最大值多一个,直到该值在新类型的范围内。” (第 6.3.1.3/p2 节)
因此,有一个明确定义的过程可以将参数表达式转换为(可能有符号的) int 参数,以及一个明确定义的过程,用于将该值转换为 unsigned char 。因此,我认为上面介绍的程序是完全定义好的。
为了证实,给定格式说明符 fprintf%c 的行为定义如下(第 7.21.6.8/p8 节),强调补充:

the int argument is converted to an unsigned char, and the resulting character is written.


如果要应用提议的限制性解释,使上述程序未定义,那么我相信人们将被迫还争辩说:
void f(char c) {
printf("This is a '%c'.\n", c);
}
也是UB。然而,我认为几乎每个 C 程序员都写过类似的东西,而没有三思而后行。
问题的关键部分是第 7.12.6.1/p9 节(以及第 7.12.6.1 节的其他部分)中的“参数”是什么意思。 C++ 标准稍微精确一些;它指定如果一个参数受到默认参数提升,“参数的值在调用之前被转换为提升的类型”,我解释为在考虑调用时(例如,调用 fprintf ),参数现在是提升的值。
我认为 C 实际上并没有什么不同,至少在意图上是这样。它使用诸如“参数被提升”之类的措辞,并且至少在一个地方使用“提升后的参数”。此外,在可变参数函数的描述中( va_arg 宏,第 7.16.1.1 节),对参数类型的约束在括号中被注释为“实际下一个参数的类型(根据默认参数提升)”。
我会自由地同意所有这些都是(a)对不够精确的语言的微妙阅读,以及(b)计数跳舞的天使。但是我认为声明标准用法(例如使用 %cchar 参数是“技术上”UB)没有任何值(value);这改变了 UB 的概念,很难相信这样的禁令是故意的,这让我相信这种解释不是故意的。 (而且,也许应该在编辑上更正。)

关于c - 1 字节有符号数的 printf 格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28387867/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com