计算机如何分配两个变量,我们如何计算两个变量之间的距离?

Văn*_*Bùi 1 c c++ cpu-architecture

当我试图检查两个变量之间的差异时,我发现了一些有趣的东西(你可以在下面的代码中看到)

#include <stdio.h>
#include <conio.h>
int main() {
    int a, b;  
    printf("%d", (int)&a - (int)&b);
    getch();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

每次,结果是12.我不知道为什么结果是12,我认为结果必须是4(或-4).我的电脑是64位,请解释一下.

use*_*738 6

没有没有办法,你可以说,其结果必然是4,只是因为你知道sizeof int4你的情况.

没有符合标准的,可移植的方式来做你正在寻找的东西(获得两个int变量的地址之间的差异,而不是任何数组的一部分).

int在两个连续行中声明两个变量并不意味着它们将连续放入存储器中.订购可能很有可能与您的预期不同.(在这种情况下,int a,b我在这里谈论).如果您希望ints在内存中相邻,则数组(如int ab[2])是ISO C保证在所有实现中为您提供的唯一选项.(在大多数C实现中,您也可以使用a struct,但理论上这不是完全可移植的.2)


正如所指出的,这段代码是类型转换指针int,调用实现定义的行为.另请注意,有符号整数溢出是UB,并且无法保证int可以保存特定系统中的地址.因此,intptr_t应该是一种安全的方法来避免UB并通过减去单独对象的地址的整数值来获得仅仅实现定义的结果.

提到的好处是,如果我们考虑架构实现平面寻址(就像实际使用中的几乎每个C实现一样),那么我们可以简单地将指针转换为intptr_t它并将其减去以得到结果1.但正如它所说 - 标准从未限制这种特定的内存布局(它不要求架构如此) - 更加健壮并适用于大量系统.在我们认为没有平坦地址空间的架构中的实现可能存在某些需要它以复杂方式访问元素的问题之前,所说的都是正确的.

注:如果您运行这段代码有gcc带或不带不同的优化参数(-O3,-O2等),你可能会得到期望的结果+4-4.这必须是编译器特定的情况,它给你这个结果.(很可能不是gcc).


脚注

  1. 将对象地址转换为整数是一个2阶段的过程:转换为void *第一个,然后转换为整数intptr_t/uintptr_t.要打印两个这样的整数的差异,请使用PRIdPTR/PRIuPTR. intptr_t并且uintptr_t是可选类型,但自C99以来非常常见.如果intptr_t/uintptr_t不可用,则转换为最宽的可用类型并使用其匹配的说明符.

#include <inttypes.h>
// printf("%d", (int)&a - (int)&b);
printf("%" PRIdPTR, (intptr_t)(void*)&a - (intptr_t)(void*)&b);
// or pre-C99
printf("%ld", (long)(void*)&a - (long)(void*)&b);
Run Code Online (Sandbox Code Playgroud)
  1. struct 布局和类型大小:

    在实践中,struct intpair { int a,b; } ab;还将具有连续ab主流实现,但ISO C允许在结构布局中任意数量的填充.但它确实要求struct成员具有增加的地址,因此编译可以填充但不重新排序结构.(或者C++中的类;规则在那里是相同的).

    因此,为了最小化填充(对于速度/缓存空间效率),将成员从最大到最小排序通常是个好主意,因为许多类型的对齐要求等于它们的宽度.或者,如果要将较小的成员放在较宽的成员之前,则将它们成对/四边形分组.请记住,许多实际实现在32/64位指针和/或32/64位之间有所不同long.例如64位指针和longx86-64 Windows上的32位指针,但x86-64上的64位64位指针.当然,纯ISO C仅设置类型必须能够表示的最小值范围,并且它们的最小值sizeof1,但是大多数现代CPU(以及它们的主流C实现)已经确定为32位int.

    避免编写依赖于类似假设的代码来保证正确性,但在考虑性能时要记住这一点很有用.

  • 这就是问题本身已经显而易见的 - 如果它们不是另一个,那么很明显两者之间存在着某种关系.现在的问题是:鉴于不知道编译器会浪费堆栈空间,那里有什么,为什么?填充以保持变量对齐?其他当地人?金丝雀旗?如果您阅读链接的副本,您会发现它们之间的空间很可能用于缓冲区溢出保护.这是我从中学到的东西的答案,而不是关注为什么C++在技术上不能保证测量的原因. (3认同)
  • @coderredoc:给出了`<conio.h>`和`getch()`以避免终端在从IDE内部运行后关闭,我的猜测是Windows上的VC++.但当然唯一可以肯定的方法就是问问. (2认同)