printf()函数如何知道其参数的类型

问题描述 投票:1回答:4

考虑以下程序,

#include <stdio.h>
int main()
{
    char a = 130;
    unsigned char b = 130;

    printf("a = %d\nb = %d\n",a,b);
    return 0;
}

该程序将显示以下输出。

a = -126
b = 130

我的问题是printf()函数如何知道a的类型是签名的,b的类型是无符号的,以显示上面的结果?

c gcc printf
4个回答
4
投票

printf()不知道类型,这就是为什么你必须提供正确的格式字符串。 printf()的原型如下:

int printf(const char * restrict format, ...);

因此,具有已知类型的唯一参数是第一个,即格式字符串。

这也意味着之后传递的任何参数都受默认参数提升的影响 - 强烈简化,读取它,因为任何整数都将被转换为至少int - 或者请谷歌了解该术语以了解每一个细节;)

在您的示例中,您具有实现定义的行为:

char a = 130;

如果你的char可以代表130,那就是你在printf()的输出中看到的。提升int的价值不会改变价值。你得到一个负数,这意味着130溢出你的char。在C中转换期间溢出有符号整数类型的结果是实现定义的,您获得的值可能意味着在您的机器上,char有8位(因此最大值为127)并且有符号整数溢出导致环绕到负值范围。你不能依赖那种行为!

简而言之,负数在此行中创建 - 130的类型为int,将其分配给char转换它并且此转换溢出。

一旦你的char具有值-126,将其传递给printf()只需将其转换为int,而不是更改值。


1
投票

printf()的附加参数根据类型说明符进行格式化。有关C格式说明符的列表,请参见此处。

https://fr.cppreference.com/w/c/io/fprintf

确实,人们不会期望b在你的例子中被打印为130,因为你使用的是%d说明符而不是%u。这种惊人的行为似乎在这里解释。

Format specifier for unsigned char

我希望我能很好地回答你的问题。

编辑:我不能评论Felix Palmen在我的低声誉上的回答。默认参数提升确实似乎是关键在这里,但对我来说,除了a溢出之外,真正的问题是为什么b仍然打印为130尽管使用了签名说明符。它也可以用默认参数提升来解释,但应该更精确。


0
投票

您需要查看printfstdio.h语句的定义。你已经在评论中得到了答案printf只是将格式指向的字符串写入stdout。

它是可变函数,它使用vargas来获取可变长度参数列表中的所有参数。

你这是来自glibc from the GNU version

int __printf (const char *format, ...)
{
   va_list arg;
   int done;

   va_start (arg, format);
   done = vfprintf (stdout, format, arg);
   va_end (arg);

   return done;
}

什么是vfprintf呢?

它只是将格式指向的字符串写入流中,以与printf相同的方式替换任何格式说明符,但使用由arg标识的变量参数列表中的元素而不是其他函数参数。

有关vfprintf的更多信息


0
投票

printf()不知道参数的数据类型。它适用于您传递的格式说明符。您使用的数据类型是char(范围从-128到+127)和unsigned char(范围从0到255)。 a的输出在127之后溢出。因此输出到-126。

© www.soinside.com 2019 - 2024. All rights reserved.