我可以通过IEEE双向往返一个对齐的指针吗?

时间:2017-02-14 15:10:44

标签: c ieee-754

我可以通过双向往返任何4字节对齐的指针吗?我可以通过字符串往返任何有限的双倍吗?

具体来说,在任何使用符合C11的IEEE浮点并且静态断言都不会失败的平台上,以下程序中的断言是否保证通过?

#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>

int main(void) {
   struct {
      void *dummy;
   } main_struct;
   main_struct.dummy = 0;
   static_assert(_Alignof(main_struct) >= 4,
                 "Dummy struct insufficiently aligned");
   static_assert(sizeof(double) == sizeof(uint64_t) && sizeof(double) == 8,
                 "double and uint64_t must have size 8");
   double x;
   uint64_t ptr = (uint64_t)&main_struct;
   assert((ptr & 3) == 0);
   ptr >>= 2;
   memcpy(&x, &ptr, 8);
   assert(!isnan(x));
   assert(isfinite(x));
   assert(x > 0);
   char buf[1000];
   snprintf(buf, sizeof buf, "Double is %#.20g\n", x);
   double q;
   sscanf(buf, "Double is %lg\n", &q);
   assert(q == x);
   assert(memcmp(&q, &ptr, 8) == 0);
}

1 个答案:

答案 0 :(得分:2)

  

具体来说,在任何使用符合C11的IEEE浮点并且静态断言都不会失败的平台上,以下程序中的断言是否保证通过?

只有那些要求,那么没有。排除它的原因如下:

  • 你还没有断言指针的大小是64位或更小。
  • 没有什么说指针和双精度在内存中使用相同类型的字节序。如果指针是big-endian而double是little-endian(或者是mid-endian,或者使用其他奇怪的内存格式),那么你的移位并不排除负,无限或NaN值。
  • 指针不能保证简单地转换为整数值,低位位保证为零,只是因为它们指向对齐的值。

这些反对意见在当前的实际平台上可能有点病态,但在理论上肯定是正确的,而且你的要求清单中没有任何内容与它们相反。

例如,完全可能想象一个具有独立浮点协处理器的架构,该架构使用与主整数CPU不同的内存格式。事实上,维基百科的文章实际上states表明存在这样做的架构的真实例子。至于奇怪的指针格式,C FAQ提供了一些interesting historical examples