安全地将void *转换为int

时间:2014-11-07 10:58:08

标签: c++ casting int undefined-behavior void-pointers

如果应用程序被编译为产生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}}

2 个答案:

答案 0 :(得分:5)

是的,它可能导致未定义的行为。如果您使用intptr_t代替,则没有未定义的行为。

但是,通常您可以重写代码,以便指针指向预期的整数,而不是用于强制转换为它。

在你的第二个例子中,你有一个混蛋。您希望使用指向intptr_t的{​​{1}}或void *。不是intintptr_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);

客户已经进入可疑区域,当他将枚举投入虚空*时,该演员不会使其变得更糟。