我正在使用一个使用回调的库(ENet)。在这些回调函数中,它传递一个结构,其中包含用于用户数据的void *,供您自己使用。我想使用该变量,但不是指针。我不想分配内存,所以我可以指出它,我宁愿直接使用void *的空间来存储size_t。
但是,正如预期的那样,当我将void *变量转换为size_t变量时,我得到一个严格的别名警告。而回调的结构并没有提供一个联合来访问它作为一个非空的东西*。
我知道我可以完全禁用该警告,但我宁愿为这种特殊情况保持沉默。有没有办法编写这种类型的转换,让编译器知道它是故意的,以避免警告?
修改
以下是我尝试做的一个例子。由于我需要能够编辑用户值,因此我将其转换为size_t,同时还尝试获取对它的引用:
size_t& offset = reinterpret_cast<size_t&>(packet->userData);
这样可行,但会发出警告。
答案 0 :(得分:4)
但是,正如预期的那样,当我将void *变量取消引用到size_t变量时,我得到一个严格的别名警告。
如果你想使用void *
本身来传输一个普通的整数,你不想取消引用它,你想把它转换成一个合适的整数类型(intptr_t
是你最好的选择,因为标准保证它可以通过void *
)生存到往返。
intptr_t magic=42;
register_callback(&myfunc, (void *)magic);
// ...
void myfunc(void *context)
{
intptr_t magic=(intptr_t)context;
// ...
}
(如果你喜欢C ++风格的演员表,那些都是reinterpret_cast
)
此外,您可能在代码中做了一些奇怪的事情,因为void *
(如char *
和unsigned char *
)不受严格别名规则的约束(它们可以为任何其他指针设置别名)。
<强> 更新 强>
以下是我尝试做的一个例子。由于我需要能够编辑用户值,因此我将其转换为size_t,同时还尝试获取对它的引用:
size_t& offset = reinterpret_cast<size_t&>(packet->userData);
这样可行,但会发出警告。
不,即使假设size_t
和void *
具有相同的大小和对齐要求(无法保证),也无法轻松完成;不允许使用void *&
对size_t &
进行别名(此外,这特别狡猾,因为它隐藏在参考中)。
如果你真的需要这样做,你必须与你的编译器达成协议;例如,在gcc中,您可以使用-fno-strict-aliasing
编译只有这个文件的文件,而不是简单地禁用警告(=隐藏地毯下的潜在问题),禁用编译器关于严格别名的假设,即使指向不相关类型的指针/引用指向相同的东西,生成的代码也能正常工作。