考虑以下程序,
#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
的类型是无符号的,以显示如上所述的结果?
答案 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)
您需要查看printf
中stdio.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
的更多信息