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

时间:2018-07-26 07:31:57

标签: c gcc printf

考虑以下程序,

#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的类型是无符号的,以显示如上所述的结果?

4 个答案:

答案 0 :(得分:4)

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

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

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

这也意味着之后传递的所有参数都将受默认参数提升的约束-进行了简化,将其读取为任何整数都将至少转换为 {{ 1}} –或向Google询问该术语以了解每个细节;)

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

int

如果您的char a = 130; 可以代表char,那么您将在130的输出中看到。将值提升为printf()不会更改值。相反,您得到一个负数,这意味着int溢出了130。在C中转换期间,有符号整数类型溢出的结果是实现定义,您得到的值可能意味着在您的计算机上,char有8个位(因此最大值为char),并且有符号整数溢出导致 wraparound 到负值范围。您不能依靠这种行为!

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

一旦您的char拥有值char,将其传递给-126只会将其转换为printf(),而不会更改该值。

答案 1 :(得分:1)

CREATE TABLE defaultforTime( `creation_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `modification_time` DATETIME default now() ); 的其他参数根据类型说明符设置格式。有关C格式说明符的列表,请参见此处。

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

您的示例中确实不希望将printf()打印为b,因为您使用的是130而不是%d。这种令人惊讶的行为似乎在这里得到了解释。

Format specifier for unsigned char

我希望你的问题很好。

编辑:由于我的声誉低下,我无法就帐户评论Felix Palmen的回答。 默认参数提升确实是这里的关键,但是对我来说,除了%u溢出之外,这里真正的问题是为什么a仍被打印为b尽管使用了签名说明符。也可以使用默认参数提升进行解释,但这应该更加精确。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您需要查看printfstdio.h语句的定义。您已经在注释printf中得到了答案,只需将format指向的字符串写到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做什么?

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

有关vfprintf

的更多信息