【问题标题】:Are there any C implementations where a pointer is not represented as the memory address that the pointer points to?是否有任何 C 实现中指针不表示为指针指向的内存地址?
【发布时间】:2021-10-30 18:35:35
【问题描述】:

我在查看Why can't you do bitwise operations on pointer in C, and is there a way around this? 并注意到大多数回复都说按位运算在指针上没有很好地定义,因为指针在标准中没有很好地定义。但是,这从未出现在我的任何系统类中,而且我不知道指针可以是指针指向的内存地址的值之外的任何东西。是否有任何 C 的实现,其中指针不表示为指针指向的内存地址?

是否有计划改变这一点,以便在未来的 C 标准中明确定义指针?

【问题讨论】:

  • 已经有一些实现——虽然不幸的是我现在不能引用任何——已经实现了“智能指针”,其中指针是一个 3-5 字结构,不仅包含“真实”指针还有它指向的对象的基数和大小,以便可以进行数组边界检查。
  • 有些系统的内存以复杂的形式寻址,甚至是更大的系统/处理器表示。例如分页或分段地址。在这种情况下,C 标准定义了一个 trap 表示,它可以是访问内存所需的任何类型的数据对象。那些复杂的数据对象不能用于标准的逻辑或数学运算。
  • 我不认为“陷阱表示”是您想要的术语,@Frankie_C。正如语言规范中所使用的,这意味着“不需要表示对象类型的值的对象表示”。
  • 对于它的价值,我认为问题不在于指针没有“明确定义”,而是它们的定义不包括任意算术运算符。不过,这并不是 C 标准最近强加的限制——据我所知,算术是从未为指针定义的,即使在 K&R 时代也是如此。例如,如果您正在编写链接器或内存管理器,您总是必须使用整数类型来保存您正在对其进行算术运算的内存地址。我认为所有的改变是你现在更有可能需要明确的演员表,而且uintptr_t 存在。
  • ...因此,尽管我声称对标准的发展方式没有特别的了解,但我的猜测是指针的定义方式可能不会有太多变化。

标签: c pointers


【解决方案1】:

这里真的绝对没有问题:

  1. 你想对指针进行按位运算吗?

    您引用的链接给出了一个常见的解决方案:

https://stackoverflow.com/a/15868352/421195

但你可以通过强制转换来解决它:

#include <stdint.h>

void *ptr1;
// Find page start
void *ptr2 = (void *) ((uintptr_t) ptr1 & ~(uintptr_t) 0xfff)

对于 C++,只需使用 reinterpret_cast 而不是 C 风格的强制转换。

  1. 在“指针”的(特定于平台的!)实现恰好与“无符号整数”的实现匹配时才起作用;如果您的特定平台恰好有一个“平坦”的内存模型。

  2. 问:为什么这首先会成为一个问题?

    答:因为“指针”并不总是很容易映射到“无符号整数”(或“无符号长整数”)。

    示例:16 位 DOS 指针:

    • Near 指针:用于在 16 位机器上存储当前段内的 16 位地址
    • 远指针:通常为 32 位。 为了使用它,编译器分配一个段寄存器来存储段地址,然后分配另一个寄存器来存储当前段内的偏移量。
    • 大指针:通常也是 32 位,但可以访问外部段。
    • 你不能天真地“玩弄比特”。在远指针的情况下,一个段是固定的。在far pointer中,段部分不能修改,但在Huge中可以。

“实模式 DOS”只是“平面”内存模型不容易应用的众多(同样是特定于平台的)示例之一。

另见:

【讨论】:

    【解决方案2】:

    我在查看Why can't you do bitwise operations on pointer in C, and is there a way around this? 并注意到大多数回复说按位运算在指针上没有很好地定义,因为指针在标准中没有很好地定义。

    对于该问题的答案所说的内容,这是一个很差的描述。他们实际上说的是你不能对指针执行按位操作,因为

    • 标准说你不能
    • 它没有用或没有意义
    • [对指针的按位操作]的语义没有很好的定义
    • 该标准没有对指针的表示提出要求

    从中得到的主要信息是,您不能对指针执行按位操作,因为语言规范没有定义这种操作的含义。为什么会这样?您认为旋转地址位的意义或意义是什么?如果有的话,结果会指向什么?结果必须在什么条件下才有效?

    但是,这从未出现在我的任何系统类中,而且我不知道指针可以是指针指向的内存地址的值。

    语言规范用对象地址标识指针值,但语言规范的含义不一定是可以用作需要地址的 CPU 指令的操作数的对象类型。有一些 C 实现,它们有所不同。

    您似乎还假设了一个平坦的地址空间,因此将“地址”解释为(单个)数字是合理的。过去和现在都不是这样的机器架构。

    即使考虑对 C 指针执行按位操作,也需要考虑错误的抽象级别。

    是否有计划改变这一点,以便在未来的 C 标准中明确定义指针?

    指针已经针对它们所服务的目的进行了很好的定义。它们不是整数,也不打算被视为整数。这不太可能改变,因为它不会起到有用的作用。他们的表示不太可能比现在更具体,因为这会适得其反。

    【讨论】:

    • 这是一个糟糕问题的好答案:)
    【解决方案3】:

    是否存在指针不表示为指针指向的内存地址的任何 C 实现?

    通常,不,这是指针的基本思想。您可以将NULL 视为我们在逻辑上用作不是地址的指针的示例。在安全上下文中,指针可以被加密或低位用作动态分析的标记。这是一个example。所以在这些上下文中,指针仍然表示地址,但在静止时可能看起来不像地址。

    是否有计划改变这一点,以便在未来的 C 标准中明确定义指针?

    标准非常清楚指针代表什么。在section 6.2.5 中,它描述了一个指针,如下所示

    指针类型可以派生自函数类型或对象类型,称为引用类型。一种 指针类型描述一个对象,其值提供对被引用实体的引用 类型。从引用类型 T 派生的指针类型有时称为“指向 T 的指针”。

    因此,任何不引用对象的指针的使用都是对标准的滥用。

    【讨论】:

    • 这个答案似乎在内部不一致。一方面,它开始否认存在不表示为内存地址的指针实现。然后它立即转身说实际上存在或可能是指针表示,它们本身不是内存地址,而是仅与地址相关。当然,指针表示与内存地址有关,因为正如这个答案所说,这就是指针的本质。
    • 但也许这个答案遗漏的最大的事情是挑战 OP 的明显假设,即地址是一个数字。已经有地址是不是(单个)数字的硬件架构,并且一些这样的机器仍在运行。 C 的计算模型中的所有内容都是numeric,因为所有对象表示都可以作为char 的序列访问,这是一种数字类型,但是旋转地址而不是旋转字符串的位。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多