使用printf函数通过%u格式说明符打印无符号字符是否安全?

3

所以,我意识到%u用于打印一个unsigned int。在大多数系统上,unsigned int通常不止一个字节(我认为通常为32位/4字节)。而unsigned char始终为一个字节。那么,使用%u格式说明符将字节打印成数字是否安全?类型提升会启动吗?还是可变参数列表会弄乱事情?以下是一个简单的示例:

#include <stdio.h>

int main()
{
    unsigned char val = 'A';
    printf("%u", val);  // is this safe?
}

假设使用 ASCII 编码,输出应该是65。然而,由于%u技术上是针对unsigned int而不是unsigned char,我很好奇是否存在获取垃圾字节或以意外方式访问堆栈的情况。

1
您可以使用%hhu表示无符号字符。或者您可以将无符号字符转换为无符号整数并使用%u。我猜想您所使用的方法也许可以运行,但这不是一个好的实践方式。 - pmacfarlane
@EricPostpischil printf()是C语言函数;如果调用代码是C ++,应该使用哪个适当的标签? - Jeremy Friesner
4
@JeremyFriesner 代码被编译成的语言 - Kevin
5
@JeremyFriesner:C++标准通过引用包含了某些版本的C标准,或者至少是其中的一部分,但它可能会指定自己的规则来改变从C中获取的东西。因此,“printf”不是“一个C函数”。在使用C时,“printf”应符合C标准的规则(或其他正在使用的C规范),并且对它的调用将使用C规则。在使用C++时,“printf”应符合C++标准的规则(或其他C++规范)。这两种语言已经分道扬镳,并继续分歧。 - Eric Postpischil
我标记了两个标签,因为我在两个语言中都编写代码,并且这种行为似乎在两种语言中是相同的,因为根据我的理解,printf函数是相当一致的,而且问同样的问题两次并用不同的标签似乎很愚蠢。但如果必须选择一个的话,我会选择c++,因为我们的大部分代码已经转换成了c++,但我仍然为少量的低级别和遗留程序使用一些c代码。 - alrav
在我看来,C++比C更适合低级编程(当然,需要一些努力避免在C++中使用可能不适合低级编程的功能,例如I/O流设施、RTTI设施或try/catch异常以进行流控制咳咳)。对于传统项目…它们就是它们。 - Eljay
1个回答

3

%u 需要一个 unsigned int,所以在将 unsigned char 传递给 %u 时,您需要进行类型转换,例如:

printf( "%u", (unsigned int) val );

传递原始的 unsigned char 时,它很可能在推入调用堆栈时被晋升为与 unsigned int 大小相同的类型,此时 %u 可能可以正常工作,但是您不应该依赖这种行为。最好一开始就传递正确的类型。

或者,您可以使用 %hhu(C99+),它期望一个 unsigned char,例如:

printf( "%hhu", val );

5
当直接传递无符号字符时,它很可能会被提升为无符号整数的大小。这将保证其被提升为intunsigned int。而且,unsigned intint的大小是保证相同的吗? - ikegami
1
在 Stack Overflow 中,将 unsigned char 强制转换为 unsigned int 以获得与 %u 一起使用的保证行为已经是标准做法了。但是,C 2018年版6.3.1.1中指出:“以下表达式中可以使用具有整数类型(不是 intunsigned int)的对象或表达式,其整数转换等级小于或等于 intunsigned int 的等级...”,并且 val 是一个整数类型的对象,其转换等级低于 intunsigned int,因此可使用 unsigned int - Eric Postpischil
1
请注意,现在答案已标记为C++,而答案和评论引用了C标准。 - ikegami
3
这不仅仅可能,而且是必需的(由所有标准版本的C和C++所要求)。 - n. m.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接