C 固定尺寸浮球/双浮球,便于携带

C 固定尺寸浮球/双浮球,便于携带,c,floating-point,portability,C,Floating Point,Portability,我最近学习了固定大小的整数,并计划在多年前编写的一个旧程序中使用它们 浮动和/或双精度是否有固定大小的int的等价物? 我的计划是在程序的大部分使用“本机类型”int、float、double,并且仅在考虑可移植性时指定固定大小的类型(如二进制文件的读/写)。 我使用二进制文件存储数据,如:日期yyyymmdd(souint32)、标志[0,4](souint8)、字符串(以null结尾的字符串)和货币(现在是double) 关于可移植性,程序的“可移植性”是指它可以被编译(或交叉编译)并在不同

我最近学习了固定大小的整数,并计划在多年前编写的一个旧程序中使用它们

浮动和/或双精度是否有固定大小的int的等价物?

我的计划是在程序的大部分使用“本机类型”
int、float、double
,并且仅在考虑可移植性时指定固定大小的类型(如二进制文件的读/写)。 我使用二进制文件存储数据,如:日期yyyymmdd(so
uint32
)、标志[0,4](so
uint8
)、字符串(以null结尾的字符串)和货币(现在是
double

关于可移植性,程序的“可移植性”是指它可以被编译(或交叉编译)并在不同的平台上运行。到目前为止:linux、windows、android(本机通过没有GUI的终端仿真器)和OpenBSD(strcat/strcpy只需要在两行中被strlcat/strlcpy替换)。
我担心如果我在linux x86_64、android arm某物、windows 32某物等之间使用相同的二进制数据文件,存储的float/double会发生什么情况。。。我想有一种方法来强制二进制文件中浮点值的唯一大小和表示形式。

大多数浮点值是IEEE 754、64位或32位。但是,如果处理器中的浮点单元不兼容,则没有切实有效的方法使其兼容,因此程序在不同的机器上运行时将产生略有不同的结果。(这实际上是对声音程序的一个很好的测试——如果结果因为浮点错误而显著不同,那么您处理浮点操作的能力就很差)


但是,您可以在二进制文件中以可移植的方式加载并保存与IEEE 754最接近的表示形式。此处维护货币代码,建议进行特殊处理。选择固定宽度整数类型以满足范围需求(
int64\u t
int32\u t
),并按最小货币单位进行缩放。如果代码仅存储/读取如下值


如果定义了
\uuu STDC\u IEC\u 559\uuuu
,则为是,否则为否。需要有关FP便携性要求的更多详细信息。松散地说:建议将货币存储为字符串。IEEE浮点数标准在今天是普遍存在的,除了在一些非常便宜的嵌入式处理器中。因为您正在读取文件,所以可以忽略它们。您不能完全忽略的是字节顺序(也称为endiness),这也是固定大小整数的问题。@chux:Post-edited以明确可移植性。@Hans-Passant:我从未想过endiness。我现在正在考虑将数据存储在纯文本文件中…相关问题是否有帮助?如果主机使用的是非标准浮点格式,则此指令引入的重复舍入错误可能会导致糟糕的结果。使用整数进行计算会更好,正如问题所指出的,对于整数,
stdint.h
中有固定大小的定义,在任何兼容平台上都能正常工作,而不是依赖于被认为不可靠的类型。@Pascal Cuoq:这是科学计算的情况,对吗?在我的例子中,我只存储短小数:123.12这取决于您的FPU是否可以精确表示0.5、0.25等等。否则,可能会有严重的错误积累。小数不能精确地用二进制浮点表示,但是如果只需要5位小数,那么错误就不太重要了。你的答案回答了我的问题,但我发现我的问题也与持久性有关。使用字符串似乎是存储数据的最便捷的解决方案。
void Store_int32(int32_t x); // Handles int32_t in endian independent method
int32_t Get_int32(void);     // Handles int32_t in endian independent method

void Store_Currency(double c) {
  if (c < INT32_MIN/100.0 || c > INT32_MAX/100.0) Handle_RangeError();
  Store_int32(round(c*100.0));
}

double Get_Currency(void) {
  Get_int32()/100.0;
}
void Store_double(double c) {
  char s[100];
  sprintf(s, "%a", c);                         // 0x1.ec7ae147ae148p+6
  // or
  sprintf(s, "%.*e", DBL_DECIMAL_DIG - 1, c);  // 1.2312000000000000e+02
  Store_string(s);
}

double Get_double(void) {
  char s[100];
  Get_string(s, sizeof s);
  double x;
  sscanf(s, "%f", &x);  // %f reads decimal and hexadecimal FP formats.
  return x;
}