使用非零值初始化 void 指针的正确(或最安全)方式?

correct (or safest )way of initializing void pointer with non-zero value?

以下作品:

void* p = reinterpret_cast<void*>(0x1000);

但看起来 'incorrect/unsafe' 例如。 0x1000 是 int 而不是 uintptr_t,我可以解决这个问题,但是有没有 better/safer 转换方法?

0x1000 is an int and not even uintptr_t, I could fix this, but is there a better/safer method of casting

0x1000int,在 reinterpret_cast<void*>(0x1000) 中,编译器发出符号扩展指令(此处符号为 0)或带有立即操作数的普通寄存器加载指令,使值与 void* 一样宽。

出于多种原因,编译器不可能知道 0x1000 是否表示有效地址,因此它必须遵守并假定它是有效地址。

reinterpret_cast 将表示地址的整数转换为指针是目前的做法。

您可以使用 reinterpret_cast.

从整数创建指针

但是,不指向现有对象的指针(或数组中最后一个元素之后的 1 个对象被认为是虚构数组中为此目的的唯一元素,或者是空指针)具有无效的指针值。取消引用是 UB,其他具有无效指针值的操作是特定于实现的,因此您需要确保您的编译器允许您对这些指针执行的操作。

void* p = reinterpret_cast<void*>(0x1000); // invalid pointer,
                                          // operations on it are implementation defined

§6.7.2 Compound types [basic.compound]

  1. [...] Every value of pointer type is one of the following:

    3.1 — a pointer to an object or function (the pointer is said to point to the object or function), or

    3.2 — a pointer past the end of an object (8.5.6), or

    3.3 — the null pointer value (7.11) for that type, or

    3.4 — an invalid pointer value

§8.5.1.10 Reinterpret cast [expr.reinterpret.cast]

  1. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. [...]
  2. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.

您可以将整数转换为指针,但如果生成的指针值不指向现有对象(或指向对象之后的对象),则生成的指针具有无效值。

现在关于您可以对无效指针执行的操作:

§6.6.4 Storage duration [basic.stc]

  1. [...] Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior 35

35) Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.


这个 post 被大量编辑,因为它在第一次迭代中是错误的。热烈感谢社区对我的纠正和挑战。

tl;dr:您可能不应该这样做。

The following ... looks 'incorrect/unsafe' ... is there a better/safer method of casting ?

正如另一个答案所指出的,就具有实现定义的行为而言,这是“不正确的”。另外,您使用的是幻数。

但我相信问题不在于选角。我真的有点怀疑你需要用文字地址初始化一个 void* 变量。为什么?

  • 如果该地址有某种类型化的值,则不要使用 void *,而是使用类型化指针。即使您稍后想将该指针传递给 memset()memcpy() 或什至某些采用 void * 的回调函数 - 延迟类型擦除。

  • 你从哪里得到这个数字的?你肯定知道 magic numbers are bad,对吧?好吧,至少使用像

    这样的东西
      constexpr const uintptr_t sound_card_memory_mapped_buffer_address { 0x1000 };
    

    这解决了您的一个问题(不是 uintptr_t),而且阅读起来也更清晰,即使您使用 void *:

      void* p = reinterpret_cast<void*>(sound_card_memory_mapped_buffer_address);
    
  • p 是一个糟糕的变量名称选择。根据用途重命名。

  • 你真的需要初始化 p 吗? :

    • 如果你现在不使用它,为什么还要初始化它?尝试在它即将被使用(如果有的话)之前不声明它。

    • 如果您要使用它,为什么还要声明它?尝试:

          do_something_with(sound_card_memory_mapped_buffer_address);
      

      看不到 p

很明显,我的问题多于答案,因为你只给了我们一条线。