使用非零值初始化 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
0x1000
是 int
,在 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]
[...] 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]
- A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.
[...]
- 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]
- [...] 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
。
很明显,我的问题多于答案,因为你只给了我们一条线。
以下作品:
void* p = reinterpret_cast<void*>(0x1000);
但看起来 'incorrect/unsafe' 例如。 0x1000 是 int
而不是 uintptr_t
,我可以解决这个问题,但是有没有 better/safer 转换方法?
0x1000 is an
int
and not evenuintptr_t
, I could fix this, but is there a better/safer method of casting
0x1000
是 int
,在 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]
[...] 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]
- A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. [...]
- 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]
- [...] 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
。
很明显,我的问题多于答案,因为你只给了我们一条线。