如何保证C中双精确的大小?

时间:2017-11-08 18:59:32

标签: c

所以,我知道stdint.h标头中的类型提供了标准化的宽度整数类型,但是我想知道用什么类型或方法来保证double或其他浮点的大小跨平台类型?具体来说,这将处理void*

中的打包数据
#include <stdio.h>
#include <stdlib.h>

void write_double(void* buf, double num)
{
  *(double*)buf = num;
}

double read_double(void* buf)
{
  return *(double*)buf;
}


int main(void) {
  void* buffer = malloc(sizeof(double));
  write_double(buffer, 55);
  printf("The double is %f\n", read_double(buffer));
  return 0;
}

在上面的程序中说,如果我将void*写入文件或者是否在另一个系统上使用,是否会有一些标准方法来保证浮点类型的大小或双倍?

4 个答案:

答案 0 :(得分:5)

  

如何保证C中双精确的大小?

使用_Static_assert()

#include <limits.h>

int main(void) {
  _Static_assert(sizeof (double)*CHAR_BIT == 64, "Unexpected double size");
  return 0;
}
自C11以来

_Static_assert可用。否则代码可以使用运行时断言。

#include <assert.h>
#include <limits.h>

int main(void) {
  assert(sizeof (double)*CHAR_BIT == 64);
  return 0;
}

虽然这可以确保double的大小为64,但并不能确保IEEE 754 double-precision binary floating-point format遵守。

代码可以使用__STDC_IEC_559__

  

定义__STDC_IEC_559__的实现应符合本附件中的规范.C11附件F IEC 60559浮点运算

然而,这可能过于严格。许多实现都遵循大部分标准,但仍然没有设置宏。

  

是否有一些标准方法可以保证浮点类型的大小或双倍?

最好的保证是将FP值写为十六进制表示或具有足够十进制数的指数。见Printf width specifier to maintain precision of floating-point value

答案 1 :(得分:3)

浮点类型的问题是C标准没有指定它们应该如何表示。不需要使用IEEE 754

如果您在使用IEEE 754的系统和不使用IEEE 754的系统之间进行通信,即使大小相同,您也无法在一个系统上进行通信而在另一个系统上进行通信。

您需要以已知格式序列化数据。您可以使用LightGBM将其转换为文本格式,也可以进行一些数学计算以确定基数和尾数并存储它们。

答案 2 :(得分:1)

浮点值在IEEE标准浮点运算(IEEE 754)中定义,并具有标准尺寸:

还存在以下内容:

此格式在C11标准,附件F&#34; IEC 60559浮点运算&#34;中重复使用。 ISO / IEC 9899:2011(en)。

答案 3 :(得分:0)

为什么在运行时使用CHAR_BIT并断言?我们可以在编译时这样做。

void write_double(void* buf, double num)
{
   char checkdoublesize[(sizeof(double) == 8)?1:-1];
   *(double*)buf = num;
}

您的代码仍未定义,因为它不保证IEEE或字节序,但它会捕获一个糟糕的双倍大小。如果你的平台足够新用于htonq,这将允许字节序工作

void write_double(void* buf, double num)
{
   char checkdoublesize[(sizeof(double) == 8)?1:-1];
   *(int64_t*)buf = htonq(*(volatile int64_t*)&num);
}


double read_double(void* buf)
{
   int64_t n = ntohq(*(int64_t*)buf);
   return *(volatile double*)&n;
}

其中volatile只是告诉编译器的最短路径,实际上定义了指针强制转换。通常它无论如何都是正确的,但在N内联级别之后可能不会再这样了。