使用指针解除引用生成的模糊输出?

时间:2017-01-19 08:00:01

标签: c pointers output dereference

我遇到了以下程序,无法理解输出是怎样的-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

我希望它能读取四字节整数的第一个字节。

二进制表示中的

168300000000 00000000 00000110 10010011。因此,读取第一个字节意味着输出应为0 1683。在幕后发生了什么,我听到了一些关于架构字节序的内容,但无法遵循它。

6 个答案:

答案 0 :(得分:6)

整数1683等于0x00000693int在现代系统上通常为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的无符号十进制值为147147 - 256等于-109

答案 1 :(得分:2)

请注意1683 = 0x693

如果我们假设:

  • 您的硬件架构是Little-Endian
  • 您的平台将CHAR_BIT定义为8

然后char中的第一个0x6930x93

此时请注意:

  • 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指的是哪一个? 0000011010010011?这取决于:

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 address00000110位于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