Printf 执行隐式转换

问题描述 投票:0回答:3

在下面的代码片段中,为什么我们得到 600 的输出?两个问题将帮助我理解这种行为。

  1. 我指定变量b的类型为uint8_t,为什么数学运算不限制为同一类型?
  2. 我认为 PRIu8 是打印 uint8_t 的正确类型,为什么它不起作用?

我希望得到答案 88,这是循环超出 uint8_t 范围的结果

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

void main()
{

    uint8_t b = 200;
    printf("%" PRIu8 "\n",b+b+b);
    printf("%" PRIu8 "\n",3*b);

}

gcc 版本 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)

c printf unsigned-char conversion-specifier
3个回答
2
投票

在我看来这是一个库错误。

在 MS Visual Studio 中,宏

PRIu8
按原样扩展为
hhu
,您将获得预期的结果。

有趣的是,如果要使用 clang 那么你是否会编写 example

printf("%" PRIu8 "\n",( uint8_t)(b+b+b));

什么时候你会得到预期的结果。


1
投票

在 C 中,无论何时调用带有省略号 (

...
) 参数的函数,例如 printf,所有这些参数都将进行 默认参数提升。这意味着任何较小的整数类型都将转换为
int
并以这种方式传递。所以在 printf 中,
h
类型前缀是无关紧要的——它们将被 printf 忽略并且没有任何效果(因为参数必须是
int
无论如何)。

此外,任何算术运算符(如

+
*
)都会发生较小整数类型的相同转换,并且生成的操作将以
int
精度执行,给出
int
结果。

要获得预期的结果,请将其显式屏蔽为适当的大小:

printf("%u\n", (b+b+b) & 0xff);

0
投票

如果我们看一下 inttypes.h,我们会发现以下内容:

# define PRIu8      "u"

所以这个格式说明符不包含任何长度修饰符。这在其相应参数的上下文中是有意义的,因为不可能将

uint8_t
传递给可变参数函数。因为这种类型的等级比
int
小,所以这种类型的值将提升为
int
。这种提升也发生在表达式
b+b+b
3*b
中。

如果你明确地为一个

char
使用长度修饰符,你会得到预期的结果。

printf("%hhd\n",b+b+b);
printf("%hhd\n",3*b);
© www.soinside.com 2019 - 2024. All rights reserved.