C / C ++中unsigned关键字的混淆

时间:2014-07-27 07:18:42

标签: c++ c

考虑以下两个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;
}

3 个答案:

答案 0 :(得分:12)

每个printf格式说明符都需要某个特定类型的参数。 "%d"需要int类型的参数; "%u"需要unsigned int类型的参数。传递正确类型的参数完全是您的责任。

unsigned int i = -12;

-12的类型为int。初始化会隐式地将该值从int转换为unsigned int。转换后的值(正数和非常大)存储在i中。如果intunsigned 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"适用于floatdouble参数的原因。

规则是这样一个狭义的无符号类型的论证,通常(但不总是)被提升为(签名)int

unsigned char a=200, b=200, c;

假设8位字节,ab设置为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和算术运算符的输入参数的一致性。

关于您的第二个示例:执行以下步骤

  1. double运算符要求(printf+个操作数扩展为(unsignedchar个值(这些值是4个字节的整数)我认为。)
  2. 结果总和为4字节unsigned中的400。
  3. 上述总和中只有最不重要的1个字节可以放入int,因此unsigned int的值为unsigned char c
  4. c要求将所有较小的整数参数扩展为400 % 256 == 144,因此printf接收的是4字节int中的400个。
  5. printf说明符将上述参数打印为“400”。
  6. Google提供“默认参数提升”了解详情。