【发布时间】:2014-11-07 10:58:07
【问题描述】:
如果编译应用程序以产生 x32 图像,则根据架构整数类型可能是 16 位宽、32 位宽或超过 2 字节的任何值。 void* 的大小将为 4(在 x32 上始终为 4???)。这意味着将int 传递给void* 很好,但如果事实证明在给定架构上void* 比int 宽(标准只保证至少2 个字节),则面对
C 标准 n1124 § 6.3.2.3 指针
5 整数可以转换为任何指针类型。除了作为 先前指定,结果是实现定义的,可能不是 正确对齐,可能不指向被引用的实体 类型,并且可能是一个陷阱表示。56)
6 任何指针类型都可以转换为整数类型。除了作为 之前指定的,结果是实现定义的。如果 结果不能用整数类型表示,行为是 不明确的。结果不必在任何值的范围内 整数类型。
将void* 转换为int 可能会在以下sn-p 中产生未定义的行为。
typedef enum tagENUM
{
WSO_1,
WSO_2,
//...
WSO_COUNT
} ENUM;
/* I cannot change handler signature because this is callback. I have to cast void*
* to ENUM however inside */
void handler( int i, int j, void *user_data)
{
ENUM mOperation;
mOperation = (ENUM)reinterpret_cast<int>(user_data);
}
// somewhere
handler( 1, 2, (void*)WSO_1); // UB? We can imagine that someone passes to handler
// (void*)WSO_131072 which don't fit into 16 bits
// So is there a place opened for UB?
如果这是正确的,那么鼻恶魔的可能性就打开了 - 那么我该如何安全地编写这个演员表?我可以使用intptr_t 来确保结果合适吗?
void handler( int i, int j, void *user_data)
{
ENUM mOperation;
uintptr_t p_mOperation = reinterpret_cast<uintptr_t>( user_data);
if ( p_mOperation > WSO_COUNT ) {
send_error(conn, 500, http_500_error, "Error: %s", strerror(ERRNO));
return;
}
mOperation = static_cast<ENUM_WS_OPERATION>( p_mOperation); // now safe?
【问题讨论】:
-
void*参数不旨在直接传递数据。只需传递您的整数 address 而不是值,就可以了。你正在尝试的东西永远不会正常工作,这是 x86 世界采用 64 位速度缓慢的主要原因。 -
我知道我可以,但我的问题是关于这种情况 - 有没有 UB 的地方?我必须假设有人可以通过 void* 背后的任何东西 - 我如何防止 UB?
-
引用的部分清楚地表明它是定义的实现。
-
"
void*的大小将始终为 4?" - 不,并非总是如此。仅在具有 32 位内存地址空间的平台上。 -
嗯,在这种情况下,答案是肯定的。但是请注意,C++ 标准不保证
int的大小为 4(我个人使用的平台只有 2)。
标签: c++ casting int undefined-behavior void-pointers