我遇到了以下程序,无法理解输出是如何-109 1683
的。输出结果如何?
#include <stdio.h>
int main()
{
int k = 1683;
char *a = (char *)&k;
int *l = &k;
printf("%d " , *a);
printf("%d" , *l);
}
Output is : -109 1683
取消引用指针a
如何给我-109
?
我希望它读取四个字节整数的第一个字节。
二进制表示中的1683
是00000000 00000000 00000110 10010011
。所以读取第一个字节意味着输出应该是0 1683
。幕后发生的事情,我听到了一些关于建筑字节序的事情,但无法理解。
>整数1683
等于0x00000693
(在现代系统上int
通常是32位)。在小端系统(如 x86 和 x86-64)上,它被布置在内存中,例如
+------+------+------+------+------+------+------+------+ |0x93 |0x06 |0x00 |0x00 |0x00 |0x00 |0x00 |0x00 | +------+------+------+------+------+------+------+------+
当你初始化指针a
时,你让它指向该序列中的第一个字节,包含值的字节0x93
,所以这就是你取消引用a
时得到的值。
所以现在来谈谈价值0x93
如何变得-109
的问题。有两个原因:一个是编译器char
signed
(如果是有符号或无符号类型,则char
编译器相关)。第二个原因是因为二进制的补码算术。二进制补码是一种能够在二进制机器(如现代计算机)上编码有符号整数的方法。
基本上,对于单个 8 位字节,您可以通过取(无符号)十进制值减去 256 (28) 来获得负值。0x93
的无符号十进制值为147
,147 - 256
等于-109
。
int
至少为16 位,而char
始终为 1 个字节(不是必需的 8 位)。数字1683
的二进制形式是00000110 10010011
。由于您使用的是char*
,它将指向第一个字节。但是哪个先来呢?char
指的是哪一个?00000110
还是10010011
?这取决于:
1)如果您的系统使用小端字节顺序,它将是后者,即10010011
。
00000110 10010011
^^^^^^^^
由于您使用的是有符号char
类型,因此最高有效字节将用作"符号位",即如果它是 1,则字节表示负数。要获得人类可读的值(即以 10 为基数的数字),您需要执行两个补码。最后你会得到-109
.
2)如果您的系统使用大端字节顺序,并且它使用16位int
,它将是以前的,即00000110
。这很容易,它的 base-10 形式将是6
.
00000110 10010011
^^^^^^^^
如果它使用 32 位int
,它将为零:
00000000 00000000 00000110 10010011
^^^^^^^^
请注意,1683 = 0x693
.
如果我们假设:
- 您的硬件架构是小端序
- 您的平台将
CHAR_BIT
定义为 8
那么0x693
的第一个char
是0x93
。
此时,请注意:
unsigned
2s 补码格式:0x93 = 147
- 在
signed
2s 补码格式中:0x93 = 147-256 = -109
如果你有类似 ,
int k = 1683 ;
int *l = &k;
如果取消引用指针l
则它将正确读取整数字节。因为您声明它是指向int
的指针。它将知道sizeof()
运算符要读取多少字节。通常int
的大小是4 bytes
(对于 32/64 位平台),但它取决于机器,这就是为什么它会使用运算符sizeof()
知道正确的大小并读取。现在为您的代码
int k = 1683;
char *a = &k;
int *l = &k;
现在pointer p
指向y
,但我们已经声明它是指向char
的指针,因此它只会读取一个字节或任何字节字符。 二进制1683
表示为
00000000 00000000 00000110 10010011
现在,如果您的机器是小端序,它将存储反转它们的字节
10010011 00000110 00000000 00000000
10010011
在address 00
Hypothetical address
,00000110
在address 01
,依此类推。
BE: 00 01 02 03
+----+----+----+----+
y: | 00 | 00 | 06 | 93 |
+----+----+----+----+
LE: 00 01 02 03
+----+----+----+----+
y: | 93 | 06 | 00 | 00 |
+----+----+----+----+
(In Hexadecimal)
所以现在如果你取消引用pointer a
它将只读取第一个字节,输出将被-1
,因为字节读取将被10010011
(因为我们指向signed char
,所以most-significant bit
是符号位。第一个位1
表示符号。10010011 = –128 + 16 + 2 + 1 = –109
.)如果你取消引用pointer l
它将完全读取int
的所有字节,因为我们声明它是指向int的指针。输出将1234
此外,如果您将指针 l 声明为int *l
,那么*l
将读取通常sizeof(int)
4 bytes
(取决于机器体系结构),并且*(l+1)
也会读取那么多字节。指针指向它们的任何其他数据类型char
也是如此,它们将读取大小为 、char
1 byte
的字节数。
在大多数平台上,"char"和"int"类型的大小不同。具体来说,"int"通常是 32 或 64 位(4 或 8 字节),而字符仅为 8 位(1 字节)。当取消引用"char"时,你要求程序将"int"的内存位置"解释"为"char"。
此外,"int"的字节以小端或大端(谷歌它)存储在内存中。因此,您的程序的结果将因平台而异。
如果你在x86(这是小端序)上运行你的代码,如果你将"int"设置为小于128的值,你可能会看到"正确"的值。
update:正如您正确指出的那样,int 的最低有效字节是10010011
它147
十进制,因此大于10000000
(128 十进制)。由于设置了字节的最顶层位,因此该值被解释为 2 的补码(谷歌它)负值-109
。
这是因为字节顺序:https://en.wikipedia.org/wiki/Endianness
你实际上取了字节10010011
的地址,这是-109
。