unsigned int存储有符号值

时间:2012-09-11 06:12:30

标签: 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

我不明白的是a“在我们明确说出unsigned之后如何”包含“已签名的值?

如何只在第二种情况下格式化输出呢?

4 个答案:

答案 0 :(得分:4)

正如其他人已经说过的那样,你必须始终牢记价值与其表现形式之间的差异,因为在C中这两个概念是分开的。

通过赋值,您可以将值放入特定的内存区域;使用printf()和类似的,你试着解释这样的值。

为了澄清,请尝试理解这一点:

#include <stdio.h>

int main() {   
    int val = 2181448;;
    printf("%s\n", ((char*)&val));   // * Outputs: "HI!"
    return 0;
}   

这将打印“HI!”因为你把这个赋值放在一个连续的内存区域('int'这里至少有4个字节宽)数字“2181448”,十六进制是0x00214948,即:

  • 一个值为0x00的字节,即零
  • 一个值为0x21的字节,即十进制的33,即'!'在ascii
  • 一个带有0x49的字节,即十进制的73,即ascii中的“我”
  • 最后是一个值为0x48的字节,小数为72,在ascii中为'H'。

如果你让printf把它解释为一个字符串(请注意,转换只是为了避免编译器警告)(*由于反向字节)你会看到输出这样的数字作为一个4长字符串零终止'H''我''!' '\ 0'

答案 1 :(得分:2)

-1将表示为10000000 00000000 00000000 00000001(如果int有4个字节,就像我的情况一样)。当您使用%d输出时,printf()会将其解释为 normal int ,因此它会将前导1解释为符号,并打印{{ 1}}。如果您将其输出为-1,则%u知道它是未签名的,并将前导printf()解释为1,从而导致2^32作为输出。

答案 2 :(得分:2)

因为那是printf的作用。它不知道提供的值的类型。因此,它将在a中找到它并将其解释为有符号整数,因为您通过给它%d告诉它这样做。

如果您为格式代码输入了错误的值,或者完全省略它们,那么

printf也会非常危险。你的程序会在没有任何消息的情况下崩溃。

答案 3 :(得分:2)

编译器会将-1转换为系统的正确签名数字格式,在99.9%的情况下,这将是2的补码。在具有32位整数的二进制补码系统中,-1将对应于0xFFFFFFFF。但是如果你将它存储在一个无符号变量中,你将获得42.9亿的价值。

然后,您尝试使用%d格式说明符打印42.9亿,这是为负数保留的。然后程序再次将0xFFFFFFFF解释为-1。

总结一下,在二进制级别上没有负数。根据您选择显示二进制文件的方式,您可以形成负数。尽管如此,它只是1和0:你不能在计算机存储单元中保存减号。