如果应用程序被编译为产生x32图像,那么根据体系结构整数类型可以是16位宽,32位宽或任何超过2个字节。 void*
的大小为4(在x32上总是4 ???)。这意味着将int
传递给void*
很好,但如果事实证明在给定的架构上void*
比int
更宽(只保证在void*
标准的至少2个字节)比面对
C标准n1124 § 6.3.2.3指针
5整数可以转换为任何指针类型。除了 以前指定的,结果是实现定义的,可能不是 正确对齐,可能不指向引用的实体 类型,可能是一个陷阱表示.56)
6任何指针类型都可以转换为整数类型。除了 之前指定的,结果是实现定义的。如果 结果不能用整数类型表示,行为是 未定义。结果不必在任何值的范围内 整数类型。
将int
投射到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?
来确保结果合适吗?
{{1}}
答案 0 :(得分:5)
是的,它可能导致未定义的行为。如果您使用intptr_t
代替,则没有未定义的行为。
但是,通常您可以重写代码,以便指针指向预期的整数,而不是用于强制转换为它。
在你的第二个例子中,你有一个混蛋。您希望使用指向intptr_t
的{{1}}或void *
。不是int
或intptr_t *
。
我首选的解决方案是uintptr_t *
始终指向数据;并且指向的数据类型由被调用的处理程序或其他参数确定。
答案 1 :(得分:0)
这一位:
mOperation = (ENUM)reinterpret_cast<int>(user_data);
表明你已经失去了对自己已经做过的事情的控制。你正在做一个双重演员,这总是表明发生了不好的事情(就像reinterpret_cast已经没有表明那样)。
从此不清楚你正在尝试做什么。当然(void *)对于传递不是数据的值是不合适的。它将指针传递给任意数据缓冲区,人们希望另一端的东西可以从数据中解决它需要做什么。
所以这个:
handler( 1, 2, (void*)WSO_1);
是完全错误的。
但是,鉴于WSO_1
实际上是enum
,并且我不知道void *
实际上小于枚举的任何平台,您应该是好的可以
mOperation = reinterpret_cast<ENUM>(user_data);
客户已经进入可疑区域,当他将枚举投入虚空*时,该演员不会使其变得更糟。