我遇到了以下程序,无法理解输出是怎样的-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
。在幕后发生了什么,我听到了一些关于架构字节序的内容,但无法遵循它。
答案 0 :(得分:6)
整数1683
等于0x00000693
(int
在现代系统上通常为32位)。在little-endian系统(如x86和x86-64)上,它在内存中布局如
+------+------+------+------+------+------+------+------+ | 0x93 | 0x06 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | +------+------+------+------+------+------+------+------+
初始化指针a
时,使其指向该序列中的第一个字节,即包含值0x93
的字节,以便取消引用时得到的值a
。
现在谈谈价值0x93
如何成为-109
的问题。有两个原因:一个是char
与您的编译器signed
(如果char
是有符号或无符号类型,则它依赖于编译器)。第二个原因是因为two's complement算术。 Two's complement是一种能够在二进制机器上编码有符号整数的方法,如现代计算机。
基本上,对于单个8位字节,通过将(无符号)十进制值减去256(2 8 )得到负值。 0x93
的无符号十进制值为147
,147 - 256
等于-109
。
答案 1 :(得分:2)
请注意1683 = 0x693
。
如果我们假设:
CHAR_BIT
定义为8 然后char
中的第一个0x693
为0x93
。
此时请注意:
unsigned
2s-complement格式:0x93 = 147
signed
2s-complement格式:0x93 = 147-256 = -109
答案 2 :(得分:2)
int
至少为16位,而char
始终为1个字节(not necessary 8-bit)。数字1683
的二进制形式为00000110 10010011
。由于您使用的是char*
,因此它将指向第一个字节。但那么哪个先来? char
指的是哪一个? 00000110
或10010011
?这取决于:
1)如果你的系统使用little-endian字节顺序,它将是后者,即10010011
。
00000110 10010011
^^^^^^^^
由于您使用的是签名 char
类型,因此最重要的字节将用作“符号位”,即如果它为1,则该字节表示负数。要获得人类可读的值,也就是基数为10的数字,您可以two-complement。最后你得到-109
。
2)如果您的系统使用big-endian字节顺序,并使用 16位int
,则它将是前者,即00000110
。这很简单,它的基础10形式为6
。
00000110 10010011
^^^^^^^^
如果它使用32位int
,则它将为零:
00000000 00000000 00000110 10010011
^^^^^^^^
答案 3 :(得分:1)
类型&#39; char&#39;和&#39; int&#39;大多数平台都有不同的尺寸。特别是&#39; int&#39;通常是32位或64位(4或8字节),而char仅为8位(1字节)。当取消引用“char”字样时你要求程序&#34;解释&#34;你的&#39; int&#39;的记忆位置作为&#39; char&#39;。
另外,&#39; int&#39;的字节存储在little-endian或big-endian(Google it)中。因此,您的程序结果将因平台而异。
如果您在x86上运行代码(这是小端),您可能会看到&#34;正确&#34;价值,如果你设置你的&#39; int&#39;小于128的值。
<强>更新强>
正确指出,int的最低有效字节为10010011
,其小数为147
,因此大于 10000000
(十进制128)。由于字节的最顶部位已设置,因此该值被解释为2的补码(Google it)负值-109
。
答案 4 :(得分:1)
如果你有类似的东西,
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
。
答案 5 :(得分:0)
这是因为字节顺序:https://en.wikipedia.org/wiki/Endianness
您实际上是字节10010011
的地址,即-109
。