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

Confusion in unsigned keyword in C/C++

本文关键字:关键字 unsigned c++      更新时间:2023-10-16

考虑下面两个C程序。我的问题是在第一个程序unsigned关键字打印-12,但我认为它应该打印4294967284,但它没有打印它的%d说明符。它为%u说明符打印它。但是如果我们看一下第二个程序,输出是144,而应该是-112。有些东西是可疑的unsigned关键字,我没有得到。任何帮助朋友!

#include <stdio.h>
int main()
{ unsigned int i = -12;
  printf(" i = %dn",i);
  printf(" i = %un",i);
  return 0;
}

上面的程序我从这个链接:分配负数给unsigned int?

#include <stdio.h>
int main(void)
{unsigned char a=200, b=200, c;
  c = a+b;
 printf("result=%dn",c);
 return 0;
}

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

unsigned int i = -12;

-12的类型为int。初始化隐式地将该值从int转换为unsigned int。转换后的值(非常大的正值)存储在i中。如果intunsigned int为32位,则存储值为4294967284 (232-12)。

printf(" i = %dn",i);

i类型为unsigned int,但"%d"需要一个int参数。该行为没有由C标准定义。通常,存储在i中的值将被解释为,就好像存储在int对象中一样。在大多数系统上,输出将是i = -12——但您不应该依赖于此。

printf(" i = %un",i);

这将正确打印i的值(假设前面语句的未定义行为没有把事情搞砸)。

对于普通函数,假设正确调用它们,实参通常会隐式地转换为声明的形参类型,如果这种转换可用的话。对于像printf这样的可变函数,它可以接受不同数量和类型的参数,不能进行这样的转换,因为编译器不知道期望的类型是什么。相反,实参会经历默认实参提升。如果int可以容纳int类型的所有值,则将小于CC_31类型的参数提升为int,否则提升为unsigned int。类型为float的参数被提升为double(这就是为什么"%f"floatdouble参数都有效)。

规则是这样的:窄无符号类型的参数通常(但不总是)被提升为(有符号的)int

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

假设8位字节,ab设置为200

c = a+b;

400太位了,不能放在unsigned char中。对于无符号算术和转换,超出范围的结果将缩减为类型的范围。

设置c144
printf("result=%dn",c);

c提升为int;即使参数是unsigned类型,int也足够大,可以容纳该类型的所有可能值。输出是result=144

在第一个程序中行为是未定义的。确保格式说明符与参数的数据类型匹配是您的责任。编译器会发出代码,假设你的输入是正确的;在运行时,它不需要做任何检查(通常,即使它想做,也不能做任何检查)。

(例如,库实现printf函数不知道你给它的参数是什么,它只看到一些字节,它必须假设这些字节是你使用%d指定的类型)。

你似乎在试图根据具有未定义行为的程序的输出推断unsigned意味着什么。这行不通。坚持使用定义良好的程序(最好只阅读unsigned的定义)。


在评论中你说:

可以给我任何无符号关键字的引用。我还没搞清楚概念。C/c++标准中的无符号定义。

在C99标准中读6.2.5节,从第6部分开始。

unsigned int的定义是一个整型,可以保存从0到正数UINT_MAX的值(它应该比2的幂小1),这个正数必须至少是65535,通常是4294967295

当你写unsigned int i = -12;时,编译器看到-12unsigned int的允许值范围之外,它执行一个转换。该转换的定义是加或减UINT_MAX+1,直到值在范围内。


你问题的第二部分与这一切无关。该程序中没有unsigned int;只有unsigned char .

在该程序中,200 + 200给出了400。如上所述,由于这超出了范围,编译器通过减去UCHAR_MAX+1(即256)来转换它,直到它在范围内。

printf%d%u说明符具有将输入的整数分别类型转换为intunsigned int的能力(或者,负责)。

事实上,printf(一般来说,任何可变函数)和算术运算符只能接受三种类型的参数(格式字符串除外):4字节的int, 8字节的long longdouble(警告:非常不准确的描述!)任何小于int的整型参数都被扩展到int。任何浮点参数都扩展到double。这些规则提高了printf和算术运算符输入参数的一致性。

关于你的第二个例子:以下步骤发生

  1. +运算符要求(unsigned) char操作数扩展为(unsigned) int值(我假设在您的情况下是4字节整数)
  2. 结果是4字节unsigned int的和400。
  3. 只有上述和中最低有效的1字节可以放入unsigned char c中,因此c的值为400 % 256 == 144
  4. printf要求将所有较小的整型参数扩展到int,因此printf接收到的是4字节int的400。
  5. %d指定符将上述参数打印为"400"。

Google "default argument promotion"获取更多细节