C 无符号整数存储有符号值
来自一种无类型语言(PHP),我对C中的数据类型有点困惑。我面临以下奇怪的行为C 无符号整数存储有符号值,c,C,来自一种无类型语言(PHP),我对C中的数据类型有点困惑。我面临以下奇怪的行为 //First case unsigned int a; a = -1; printf("a = %u", a); //Outputs a strange number, no problem here //Second case unsigned int a; a = -1; printf("a = %d", a); //Outputs -1 我不明白的是,一个“包含”一个有符号的值,而我们明确地说它是无符号的
//First case
unsigned int a;
a = -1;
printf("a = %u", a); //Outputs a strange number, no problem here
//Second case
unsigned int a;
a = -1;
printf("a = %d", a); //Outputs -1
我不明白的是,一个
“包含”一个有符号的值,而我们明确地说它是无符号的
仅在第二种情况下格式化输出如何才能做到这一点?将
-1
表示为类似1000000000000000000000000000001
(如果int
与我的情况一样有4个字节)。当您使用%d
输出它时,printf()
将其解释为正常整数,因此它将前导的1
解释为符号,并打印-1
。如果您将其输出为%u
,printf()
知道它是无符号的,并将前导的1
解释为2^32
,从而将4294967295
作为输出。-1将表示为1000000000000000000000000000001
(如果int
与我的情况一样有4个字节)。当您使用%d
输出它时,printf()
将其解释为正常的int,因此它将前导的1
解释为符号,并打印-1
。如果您将其输出为%u
,printf()
知道它是无符号的,并将前导的1
解释为2^32
,从而将4294967295
作为输出。因为这就是printf
所做的。它不知道提供的值的类型。因此它会将在a
中找到的数据解释为有符号整数,因为它可以通过给它%d
来执行此操作
printf
如果您为格式化代码输入了不正确的值,或者完全忽略了它们,也会非常危险。您的程序将在没有任何消息的情况下崩溃。因为这就是printf
所做的。它不知道提供的值的类型。因此它将获取在a
中找到的数据并对其进行解释作为有符号整数,因为您通过给它%d
来告诉它这样做
printf
如果您为格式化代码输入了不正确的值,或者完全忽略了它们,也会非常危险。您的程序将在没有任何消息的情况下崩溃。编译器会将-1转换为您系统的正确有符号数字格式,在99.9%的情况下,这将是二的补码。在二的补码系统上对于32位整数,-1将对应于0xFFFFFFFF。但如果将其存储在无符号变量中,将得到值42.9亿
然后尝试使用%d格式说明符打印42.9亿,该说明符保留为负数。然后程序再次将0xFFFFFF解释为-1
总而言之,二进制级别上不存在负数。根据您选择显示二进制的方式,您可以形成负数。不过,负数只能是1和0:您无法在计算机内存单元中保存减号。编译器将-1转换为系统正确的有符号数格式,格式为99.9%的情况下,这将是二的补码。在具有32位整数的二的补码系统上,-1将对应于0xFFFFFFFF。但如果将其存储在无符号变量中,则会得到42.9亿的值 然后尝试使用%d格式说明符打印42.9亿,该说明符保留为负数。然后程序再次将0xFFFFFF解释为-1
总而言之,二进制级别上不存在负数。根据您选择显示二进制的方式,您可以形成负数。不过,负数都是1和0:您无法将减号保存在计算机内存单元中。正如其他人所说,您必须始终记住值和它之间的差异s表示,因为在C中这两个概念是广泛分离的 通过赋值,您将一个值放入内存的特定区域;通过printf()和类似的方法,您尝试解释这样的值 为了澄清,请尝试理解这一点:
#include <stdio.h>
int main() {
int val = 2181448;;
printf("%s\n", ((char*)&val)); // * Outputs: "HI!"
return 0;
}
#包括
int main(){
int val=2181448;;
printf(“%s\n”((char*)&val));//*输出:“嗨!”
返回0;
}
这将打印“HI!”,因为您将赋值放在连续的内存区域(“int”在这里至少有4个字节宽)中,数字“2181448”,十六进制为0x00214948,即:
- 值为0x00的字节,即零
- 值为0x21的字节,十进制为33,ascii为“!”
- 带有0x49的字节,十进制为73,ascii为“I”
- 最后是一个值为0x48的字节,十进制为72,ascii为“H”
如果让printf将其解释为字符串(注意强制转换只是为了避免编译器警告)(*由于反向结束)您可以看到输出的数字是一个以零结尾的4长度字符串“H”“I”!“\0”,正如其他人所说的,您必须始终记住值与其表示形式之间的差异,因为在C中,这两个概念是广泛分开的 通过赋值,您将一个值放入内存的特定区域;通过printf()和类似的方法,您尝试解释这样的值 为了澄清,请尝试理解这一点:
#include <stdio.h>
int main() {
int val = 2181448;;
printf("%s\n", ((char*)&val)); // * Outputs: "HI!"
return 0;
}
#包括
int main(){
int val=2181448;;
printf(“%s\n”((char*)&val));//*输出:“嗨!”
返回0;
}
这将打印“HI!”,因为您将赋值放在连续的内存区域(“int”在这里至少有4个字节宽)中,数字“2181448”,十六进制为0x00214948,即:
- 值为0x00的字节,即零
- 值为0x21的字节,十进制为33,ascii为“!”
- 带有0x49的字节,十进制为73,ascii为“I”
- 最后是一个值为0x48的字节,十进制为72,ascii为“H”