1

来自无类型语言 (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

4 回答 4

4

正如其他人已经说过的,您必须始终牢记值与其表示之间的区别,因为在 C 中这两个概念是分开的。

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

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

#include <stdio.h>

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

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

  • 一个值为 0x00 的字节,即 0
  • 一个值为 0x21 的字节,即十进制的 33,即 '!' 在ASCII
  • 一个 0x49 的字节,即十进制的 73,即 ascii 中的 'I'
  • 最后是一个值为 0x48 的字节,它是十进制的 72,在 ascii 中是“H”。

如果您让 printf 将其解释为字符串(请注意,强制转换只是为了避免编译器警告)(*由于反向字节序)您会看到输出这样的数字作为 4 长度字符串以零结尾的 'H' 'I' '! ' '\0'

于 2012-09-11T09:08:14.507 回答
3

因为这就是这样printf做的。它不知道所提供值的类型。因此,它将获取它找到的数据并将其a解释为有符号整数,因为您通过给它来告诉它这样做%d

printf如果您为格式化代码输入了错误的值,或者完全忽略它们,也可能非常危险。您的程序将在没有任何消息的情况下崩溃。

于 2012-09-11T06:18:55.823 回答
2

-1被表示为10000000 00000000 00000000 00000001(如果int在我的情况下有 4 个字节)。当您使用 输出它时%d,将其printf()解释为普通 int,因此它将前导解释1为符号,并打印-1。如果将其输出为%uprintf()则知道它是无符号的,并将前导解释12^32,从而导致4294967295输出。

于 2012-09-11T06:17:53.357 回答
2

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

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

总而言之,在二进制级别上没有负数这样的东西。根据您选择显示二进制的方式,您可以形成负数。尽管如此,它只是一个和零:你不能在计算机内存单元中保存一个减号。

于 2012-09-11T06:22:21.047 回答