c语言 - 使用指针取消引用生成的不明确输出



我遇到了以下程序,无法理解输出是如何-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。幕后发生的事情,我听到了一些关于建筑字节序的事情,但无法理解。

>整数1683等于0x00000693(在现代系统上int通常是32位)。在小端系统(如 x86 和 x86-64)上,它被布置在内存中,例如

+------+------+------+------+------+------+------+------+ |0x93 |0x06 |0x00 |0x00 |0x00 |0x00 |0x00 |0x00 | +------+------+------+------+------+------+------+------+

当你初始化指针a时,你让它指向该序列中的第一个字节,包含值的字节0x93,所以这就是你取消引用a时得到的值。

所以现在来谈谈价值0x93如何变得-109的问题。有两个原因:一个是编译器charsigned(如果是有符号或无符号类型,则char编译器相关)。第二个原因是因为二进制的补码算术。二进制补码是一种能够在二进制机器(如现代计算机)上编码有符号整数的方法。

基本上,对于单个 8 位字节,您可以通过取(无符号)十进制值减去 256 (28) 来获得负值。0x93的无符号十进制值为147147 - 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的第一个char0x93

此时,请注意:

  • unsigned2s 补码格式:0x93 = 147
  • signed2s 补码格式中: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

10010011address 00Hypothetical address00000110address 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也是如此,它们将读取大小为 、char1 byte的字节数。

在大多数平台上,"char"和"int"类型的大小不同。具体来说,"int"通常是 32 或 64 位(4 或 8 字节),而字符仅为 8 位(1 字节)。当取消引用"char"时,你要求程序将"int"的内存位置"解释"为"char"。

此外,"int"的字节以小端或大端(谷歌它)存储在内存中。因此,您的程序的结果将因平台而异。

如果你在x86(这是小端序)上运行你的代码,如果你将"int"设置为小于128的值,你可能会看到"正确"的值。

update:正如您正确指出的那样,int 的最低有效字节是10010011147十进制,因此大于10000000(128 十进制)。由于设置了字节的最顶层位,因此该值被解释为 2 的补码(谷歌它)负值-109

这是因为字节顺序:https://en.wikipedia.org/wiki/Endianness

你实际上取了字节10010011的地址,这是-109

相关内容

  • 没有找到相关文章

最新更新