【问题标题】:How C printf function knows the integer size passed?C printf 函数如何知道传递的整数大小?
【发布时间】:2018-11-08 15:47:13
【问题描述】:

在下面的示例代码中,printf 是如何知道要为 uint8_t 打印的大小,而提到的格式只有“0x%x”,而 passd 类型是 uint32_t? printf 怎么知道第一次调用它必须打印 4 个字节,第二次调用它必须只打印 1 个字节?

uint32_t X = 0xAABBCCDD;
printf("uint32_t 0x%x\n", (uint32_t) X);
printf("uint8_t  0x%x\n", (uint8_t) X);

输出

uint32_t 0xaabbccdd
uint8_t  0xdd

【问题讨论】:

  • 它只是不打印前导零。
  • 所有小于int 的值都被提升并作为int 传递给printf(或任何其他可变参数函数)。这就是它起作用的原因。尝试使用更大的类型,你会遇到问题。

标签: c pointers printf variadic-functions


【解决方案1】:

它不知道。由于默认参数提升,在这两种情况下,您都给printf 一个[unsigned] int。您的代码相当于:1

printf("uint32_t 0x%x\n", (unsigned int)(uint32_t) X);
printf("uint8_t  0x%x\n", (int)(uint8_t) X);

推广规则是:

[6.3.1.1] 如果int 可以表示原始类型[...] 的所有值,则该值将转换为int;否则,将其转换为unsigned int

printf 此时遵循的唯一规则是不打印前导零。

请注意,将已签名的 int 映射到 %x 在技术上是未定义的行为。


1。我假设您在这里有 32 位 ints。

【讨论】:

  • uint8_t 默认提升为int,而不是unsigned int,因为提升是保值的,uint8_t 的范围总是适合int,而无需转到unsigned int .
  • @JonathanLeffler ...使其在技术上未定义的行为,因为 unsigned int 是预期的,但 int 收到了,尽管我们通常不担心这一点
【解决方案2】:

printf("uint8_t  0x%x\n", (uint8_t) X);

uint8_t 肯定是比int 等级低的类型,因此uint8_t 将被提升为int"%x" 将起作用。

//potentially invokes UB depending on platform
printf("uint32_t  0x%x\n", (uint32_t) X); 

是不可移植的代码。理论上,你不知道uint32_t 是什么真正的类型,所以你应该使用inttypes.h 中的PRIx32 宏。为了一致性/简单起见,您也可以将PRIx8 用于uint8_t

#include <inttypes.h>
#include <stdio.h>
int main()
{
    uint32_t X = 0xAABBCCDD;
    printf("uint8_t  0x%" PRIx8 "\n", (uint8_t) X);
    printf("uint32_t 0x%" PRIx32 "\n", (uint32_t) X);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-18
    • 1970-01-01
    • 2019-01-03
    • 2012-04-27
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多