我正在试图计算C标准是否要求所有地址都在同一个地址空间中。如果我有两个不同类型的对象
double d;
int i;我不能对它们的地址执行指针运算,因为它们是不同类型的指针。但是,标准说我可以将字符类型指针指向那里,并获得对象中第一个字节的地址。
char *dp = (char *)&d;
char *ip = (char *)&i;用这些方法,我可以做指针运算,例如,计算它们在内存中的距离,(dp - ip)。当然,如果双倍和整数位于同一个内存中的话。他们总是在我知道的平台上这么做,但这是否有标准的保证呢?还是只有当我的char指针指向同一类型的东西时,才允许指针算术?
发布于 2020-09-26 06:37:09
由于ASLR等因素,以及C规范中关于变量在内存中的实际位置的特殊性,您确实不能相信两个指向两个不同对象的指针之间的差异来表示任何东西。
堆栈上的东西是否以自顶向下的方式分配?当然,通常情况下,这是一个由来已久的惯例,但并不要求是这样的。它们可以是堆分配的,也可以是随机分布的。这不太可能,但允许。
在任何保护模式的操作系统中,您都看不到真正的内存地址,它们是用户空间地址,它们看起来和感觉都非常真实,但是CPU将它们重新映射到内存中的实际位置,或者甚至没有,因为该内存可能被交换到磁盘、压缩或其他由内核和CPU隐藏的更神秘和更令人困惑的东西上。
虽然可以通过malloc或calloc获取给定分配中两个位置的差异,但两个任意分配或对象之间的差异实际上是没有意义的。内核不仅添加了一个抽象层,而且它还会故意搅乱它通过地址空间布局随机化给您的分配,作为一种措施,使您的分配更加不可预测。
为什么?使缓冲区溢出错误更难武器化。
因此,如果您对内存中变量的位置感到好奇,那很好,请看一看,探索一下,但不要假设编译器、操作系统或CPU所使用的策略在将来不会发生戏剧性的变化。
在任何现代64位CPU和操作系统上,都有大量的地址空间可供使用,比如18,446,744,073,709,551,616个可能的字节,虽然其中的大部分被隔离和保留,但仍然有一个几乎用之不竭的空间。这也乘以每个进程都有自己的地址空间,所以实际上比理论上要处理的要多得多。
有趣的事实:在64位CPU开始应用之前,有一些不寻常的36位内存方案,32位操作系统和CPU可以处理超过4GB的内存,但是每个单独的进程只能“看到”4GB,因为它使用32位指针。
发布于 2020-09-26 06:43:18
指针算法仅在指针具有相同类型且指向同一对象时才定义。更具体地说,标准说:
第三条减法应当有下列情形之一:
以及:
9当两个指针被减去时,两个指针都将指向同一个数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素下标的差异。
(为了解释上面的内容,单个对象被视为一个带有一个元素的数组。)
将指针类型转换为char *将在第3条中处理约束,但指向d的指针并不指向i的元素。所以你不能减去它们。
发布于 2020-09-26 11:40:39
分配给malloc的内存可用于任何具有基本对齐要求的对象,其中包括所有“内置”类型(例如,编译器可能作为扩展提供的特殊类型),根据C 2018 7.22.3 1,因此所有这些对象都必须共享malloc使用的地址空间。
此外,任何类型的对象都可以放在结构或联合中,因此必须共享地址空间。
https://stackoverflow.com/questions/64074515
复制相似问题