考虑以下两个C程序。我的问题是在第一个程序unsigned
关键字打印-12
,但我认为它应该打印4294967284
,但它不会为%d
说明符打印它。它为%u
说明符打印它。但是,如果我们查看第二个程序,则输出为144
,其中应为-112
。有关unsigned
关键字的问题很可疑,我没有得到。任何帮助的朋友!
#include <stdio.h>
int main()
{ unsigned int i = -12;
printf(" i = %d\n",i);
printf(" i = %u\n",i);
return 0;
}
上面prorgam我从这个链接:Assigning negative numbers to an unsigned int?
#include <stdio.h>
int main(void)
{unsigned char a=200, b=200, c;
c = a+b;
printf("result=%d\n",c);
return 0;
}
答案 0 :(得分:12)
每个printf
格式说明符都需要某个特定类型的参数。 "%d"
需要int
类型的参数; "%u"
需要unsigned int
类型的参数。传递正确类型的参数完全是您的责任。
unsigned int i = -12;
-12
的类型为int
。初始化会隐式地将该值从int
转换为unsigned int
。转换后的值(正数和非常大)存储在i
中。如果int
和unsigned int
为32位,则存储的值为4294967284
(2 32 -12)。
printf(" i = %d\n",i);
i
的类型为unsigned int
,但"%d"
需要int
个参数。行为不是由C标准定义的。通常,i
中存储的值将被解释为,就好像已存储在int
对象中一样。在大多数系统上,输出将为i = -12
- 但您不应该依赖它。
printf(" i = %u\n",i);
这将正确打印i
的值(假设前一个语句的未定义行为没有弄乱)。
对于普通函数,假设您正确调用它们,如果可以进行转换,则通常会将参数隐式转换为参数的声明类型。对于像printf
这样的可变参数函数,它可以采用不同数量和类型的参数,不能进行这样的转换,因为编译器不知道预期的类型。相反,参数经历默认参数促销。如果int
可以包含该类型的所有值,则int
类型的参数将被提升为int
,否则将提升为unsigned int
。类型float
的参数将提升为double
(这就是"%f"
适用于float
和double
参数的原因。
规则是这样一个狭义的无符号类型的论证,通常(但不总是)被提升为(签名)int
。
unsigned char a=200, b=200, c;
假设8位字节,a
和b
设置为200
。
c = a+b;
总和400
太小,不适合unsigned char
。对于无符号算术和转换,超出范围的结果将减少到该类型的范围。 c
设置为144
。
printf("result=%d\n",c);
c
的值提升为int
;即使参数是无符号类型,int
也足以容纳该类型的所有可能值。输出为result=144
。
答案 1 :(得分:6)
在第一个程序中,行为未定义。确保格式说明符与参数的数据类型匹配是您的责任。编译器会发出代码,假设你做对了;在运行时它不必进行任何检查(通常,即使它想要也不能进行任何检查)。
(例如,库实现printf函数不知道你给它的参数,它只看到一些字节,并且它必须假设那些是你使用%d
指定的类型的字节。) / p>
您似乎试图根据具有未定义行为的程序的输出推断某些内容unsigned
。那不会奏效。坚持明确定义的程序(最好只阅读unsigned
的定义。)
在评论中你说:
可以给我任何unsigned关键字的参考。仍然没有让我理解这个概念。 C / C ++标准中的无符号定义。
在C99标准阅读部分6.2.5中,从第6部分开始。
unsigned int
的定义是一个整数类型,可以保存从0
到正数UINT_MAX
的值(应该小于2的幂),这必须是至少为65535
,通常为4294967295
。
当您编写unsigned int i = -12;
时,编译器会发现-12
超出unsigned int
允许值范围,并执行转换。该转换的定义是添加或减去UINT_MAX+1
,直到该值在范围内。
你问题的第二部分与所有这些无关。该计划中没有unsigned int
;只有unsigned char
。
在该计划中,200 + 200
提供400
。如上所述,由于这超出了范围,编译器通过减去UCHAR_MAX+1
(即256)来转换它,直到它在范围内。 400 - 256 = 144
。
答案 2 :(得分:-4)
%d
的{{1}}和%u
说明符具有(或负责)将输入整数类型转换为printf
的能力分别为int
。
实际上unsigned int
(通常,任何可变函数)和算术运算符只能接受三种类型的参数(格式字符串除外):4字节printf
,8字节{{ 1}}和int
(警告:非常不准确的描述!)任何大小小于long long
的整数参数都会扩展为double
。任何浮点参数都扩展为int
。这些规则改善了int
和算术运算符的输入参数的一致性。
关于您的第二个示例:执行以下步骤
double
运算符要求(printf
)+
个操作数扩展为(unsigned
)char
个值(这些值是4个字节的整数)我认为。)unsigned
中的400。int
,因此unsigned int
的值为unsigned char c
。c
要求将所有较小的整数参数扩展为400 % 256 == 144
,因此printf
接收的是4字节int
中的400个。printf
说明符将上述参数打印为“400”。Google提供“默认参数提升”了解详情。