C/ c++中unsigned关键字的混淆
Confusion in unsigned keyword in C/C++
考虑下面两个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
中。如果int
和unsigned 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"
对float
和double
参数都有效)。
规则是这样的:窄无符号类型的参数通常(但不总是)被提升为(有符号的)int
。
unsigned char a=200, b=200, c;
假设8位字节,a
和b
设置为200
。
c = a+b;
和400
太位了,不能放在unsigned char
中。对于无符号算术和转换,超出范围的结果将缩减为类型的范围。
c
为144
。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;
时,编译器看到-12
在unsigned int
的允许值范围之外,它执行一个转换。该转换的定义是加或减UINT_MAX+1
,直到值在范围内。
你问题的第二部分与这一切无关。该程序中没有unsigned int
;只有unsigned char
.
在该程序中,200 + 200
给出了400
。如上所述,由于这超出了范围,编译器通过减去UCHAR_MAX+1
(即256)来转换它,直到它在范围内。
printf
的%d
和%u
说明符具有将输入的整数分别类型转换为int
和unsigned int
的能力(或者,负责)。
事实上,printf
(一般来说,任何可变函数)和算术运算符只能接受三种类型的参数(格式字符串除外):4字节的int
, 8字节的long long
和double
(警告:非常不准确的描述!)任何小于int
的整型参数都被扩展到int
。任何浮点参数都扩展到double
。这些规则提高了printf
和算术运算符输入参数的一致性。
关于你的第二个例子:以下步骤发生
-
+
运算符要求(unsigned
)char
操作数扩展为(unsigned
)int
值(我假设在您的情况下是4字节整数) - 结果是4字节
unsigned int
的和400。 - 只有上述和中最低有效的1字节可以放入
unsigned char c
中,因此c
的值为400 % 256 == 144
。 -
printf
要求将所有较小的整型参数扩展到int
,因此printf
接收到的是4字节int
的400。 -
%d
指定符将上述参数打印为"400"。
Google "default argument promotion"获取更多细节
- Visual Studio 2015:Extern "C" 和 "export" 关键字
- C++中的"inline"关键字
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 如何确保C++函数在定义之前声明(如override关键字)
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 谷歌模拟和覆盖关键字
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 结构体 S { int align; } 之间的区别;(struct 关键字后的名称)和 struct { int al
- 如果全局变量默认是外部变量,为什么要添加"extern"关键字?
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 为什么"delete"关键字不删除节点?
- 在 c++ 中正确定义"this"关键字?
- 这个额外的关键字在这个 c++ 类声明中是什么意思?
- 在 typedef 内部使用 const 关键字和在 typedef 外部使用 const 关键字之间有区别吗?
- C++ - 为什么这里需要'template'关键字?
- C++函数的关键字?
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- 在动态分配中,在关键字new之前使用Why(unsigned char*)
- 这里的unsigned关键字的作用是什么
- C/ c++中unsigned关键字的混淆