计算机如何分配两个变量,我们如何计算两个变量之间的距离?
How does computer allocate two variables and how can we calculate the distance between two variables?
当我尝试检查两个变量之间的差异时,我发现了一些有趣的东西(你可以在下面的代码中看到)
#include <stdio.h>
#include <conio.h>
int main() {
int a, b;
printf("%d", (int)&a - (int)&b);
getch();
return 0;
}
每次的结果都是 12 .我不知道为什么结果是 12,我认为结果一定是 4(或 -4)。我的电脑是64位的,请解释一下。
不,你不可能仅仅因为你知道在你的情况下sizeof int
4
就说结果必须4
。
没有符合标准, 执行您正在寻找的操作的便携式方法(获取不属于任何数组的两个int
变量的地址之间的差异)。
在两行中声明两个int
var 并不意味着它们将连续放置在内存中。排序很可能与您预期的不同。(在这种情况下,我在这里谈论int a,b
)。如果您希望int
在内存中相邻,数组(如int ab[2]
)是 ISO C 保证在所有实现上为您提供的唯一选择。 (在大多数C实现中,你也可以使用struct
,但这在理论上不是完全可移植的。2)
如前所述,此代码将指向调用实现定义行为的指针类型化int
。 另请注意,有符号整数溢出是 UB,并且不能保证int
可以在特定系统中保存该地址。 因此,intptr_t
应该是避免 UB 并通过减去单独对象地址的整数值来获得仅实现定义的结果的安全方法。
提到的很好的一点是,如果我们认为架构实现了平面寻址(就像实际使用的几乎所有 C 实现一样),那么我们可以简单地将指针转换为intptr_t
并减去它以获得结果1。但正如它所说 - 标准从未限制过这种特定的内存布局(它不要求架构像这样) - 更加健壮并适用于大量系统。无论说什么都是正确的,直到我们认为没有平面地址空间的架构中的实现可能存在一些问题,需要它以复杂的方式访问元素。
注意:如果你运行这段代码,gcc
带有或不带有不同的优化标志(-O3
、-O2
等),你可能会得到+4
或-4
的预期结果。这必须是为您提供此结果的编译器特定情况。(很可能不是gcc
)。
脚注
- 将对象地址隐藏为整数是一个 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);
struct
布局和类型大小:在实践中,
struct intpair { int a,b; } ab;
也会对主流实现进行连续的a
和b
,但ISO C允许在结构布局中使用任意数量的填充。 但是,它确实要求结构成员具有递增的地址,因此编译可以填充但不能对结构进行重新排序。 (或C++中的类;那里的规则是一样的)。因此,为了最大程度地减少填充(为了速度/缓存空间效率),通常最好从大到小对成员进行排序,因为许多类型的对齐要求等于其宽度。 或者,如果您想将较小的成员放在较宽的成员之前,则可以将它们成对/四边形分组。 请记住,许多实际实现在 32/64 位指针和/或 32/64 位
long
之间有所不同。 例如,x84-64 Windows上的64位指针和32位long
,但在x86-64上为64/64。 当然,纯ISO C只设置类型必须能够表示的最小值范围,并且它们的最小sizeof
是1
,但大多数现代CPU(以及它们的主流C实现)已经确定了32位int
。避免编写依赖于此类假设以确保正确性的代码,但在考虑性能时记住这一点很有用。
由于该标准没有指定指向不相关对象的指针的算术,因此减去此类指针很容易产生 UB,并且它依赖于实现。
由于它依赖于实施,因此不能指望结果。
通常,根据经验,编译器会在程序堆栈上分配两个彼此靠近(并排大小)的整数。在这种情况下,对于具有平面内存架构的系统,减去地址会给我们int
的大小。
这是测试,用于检查您的程序可以为您提供什么:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main() {
int a, b;
// Print address of the variables of a and b
printf("Address of b %pn", (void *)&b);
printf("Address of a %pn", (void *)&a);
// THIS IS PRONE TO UB since pointers `&a` and '&b' not related to each other:
printf("Substructing pointers: %lldn", &b - &a );
// Now we substract addresses:
// Get the distance in memory on any architecture with flat addressing.
printf("nSubtracting addr: %lldn", (long long int)&b - (long long int)&a);
printf("Subtracting addr: %lldn", (__intptr_t)(void *)&b - (__intptr_t)(void *)&a);
printf("%" PRIdPTR, (intptr_t)(void*)&a - (intptr_t)(void*)&b);
return 0;
}
输出:
Address of b 0x7ffc2d3cd2d4
Address of a 0x7ffc2d3cd2d0
Substructing pointers: 1
Subtracting addr: 4
Subtracting addr: 4
-4
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 我可以创建一个包含两个变量的 for 循环,但时间复杂度仍然为 O(n) 吗?
- 如何更好地检查两个 char 变量是否在一组值中?
- 如何将两个字符串加在一起,就好像它们是变量一样?
- 命令行参数,cant 或两个变量
- 在 for 循环中更新两个变量时遇到问题C++
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- C++ 编译时在两个变量之间交替
- C++ 如何在包含两个变量的结构中存储与变量不同数量的值?
- 如何比较两个tm(来自ctime)变量
- 两个不同的进程,在同一地址上有 2 个 std::atomic 变量?
- 如何在 c++ 中将两个不同类型的变量分配给一个变量
- 为什么我不能使用最小和最大这两个词作为变量名称?
- 为什么一个接一个声明的两个变量在内存中不相邻?
- 在链接到两个 exe 的 dll 中共享全局变量
- C++ 两个线程,共享几个整数变量
- 为什么动态分配的两个变量的内存位置不是连续的?
- 计算两个uint8_t变量之间差值的最快方法是什么?
- 如何使用C++中不是文字的变量在数字中显示单引号和两个引号?假设 6'2" 英尺
- 是否可以在C++中使用宏交换两个变量的出现?