将 double(不是指针)转换为 void 指针

标签 c pointers casting

这样转换合法吗?

void probability(void **value)
{
    double v = 0.1234;
    *value = (void *) *(uint64_t *) &v;
}

我知道,这是一件坏事,但我 100% 确定 sizeof(double) = sizeof(void *) = sizeof( uint64_t) 在目标机器上。

最佳答案

这是未定义的行为,因为您的代码违反了严格的别名规则。

允许编译器假设指向大多数不相关类型的指针不指向同一内存。您创建了一个指向内存的 uint64_t *(转换的结果),它“实际上”是一个 double ,并且您期望从该指针读取一个值,该值与双。

严格别名规则的目的是允许编译器进行各种优化来破坏此代码 - 最有可能的是编译器可以“推断” v 未使用并且永远不会初始化它,因为它永远不会通过任何有效名称或指针访问,只能通过无效别名访问。

我没有检查过这个特定的代码,但 GCC 实际上在高度优化时确实依赖于严格的别名,并且会破坏这种代码。

解决严格别名问题的方法是使用memcpy:

assert(sizeof(*value) == sizeof(v));
memcpy(value, &v, sizeof(*value));

完成此操作后,或者如果您使用的编译器不依赖于严格的别名,或者可以避免这种依赖(--no-strict-aliasing),那你还是有问题。该标准实际上并不保证每个与地址大小相同的数值实际上都可以在 void* 中表示。例如,实现(实际上)在指针中有填充位是合法的,如果您尝试创建一个填充位中有错误值的指针值,则会崩溃。实际上,这不会发生在您称之为“正常”的任何硬件上,但是标准不允许您的代码。

关于将 double(不是指针)转换为 void 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10281329/

相关文章:

c - 一种比较 C 中未排序数组值的优雅方法?

c - 如何在 Windows 上用 C 语言从另一个程序启动一个独立的程序(在单独的控制台窗口中)?

c# - 将 C 转换为 C#

ios - 将特定类型的对象添加到 Swift 中的泛型 Array<Any>?

c++ - 为什么这个 auto_ptr 的 dynamic_cast 会失败?

c - 函数参数中的字符串

c - 用指针编辑 C 中的结构

c++ - C+ : Destructor for same instance of an object called twice

c - 找到 的输出?

c++ - 为什么我可以从 char * const 值创建 char * vector ?