0

我正在尝试在 2 个 UNIX 集群之间传输我的文件,数据是二进制形式的纯数字(双精度向量)。不幸的是其中一个系统是IBM ppc997,另一个是AMD Opteron,看起来这些系统中二进制数的格式不同。

到目前为止,我已经尝试了 3 种方法:

1-将我的文件更改为 ASCII 格式(即在文本文件中的每一行保存一个数字),将它们发送到目的地并在目标系统上再次将它们更改为二进制(它们都是 UNIX,没有行尾字符差异? ?!)

2-将纯二进制文件发送到目的地

3-使用 uuencode 将它们发送到目的地并对其进行解码

不幸的是,这些方法中的任何一个都不起作用(我在目标系统中的代码会产生垃圾,虽然它在第一个系统上工作,但我 100% 确定代码本身是可移植的)。我不知道我还能做什么?你有什么主意吗?我不是专业人士,请不要使用计算机科学家的术语!

而且:我的代码是用 C 语言编写的,所以二进制是指内存和硬盘之间的一对一映射。

谢谢

4

5 回答 5

3

如果您将内存内容写入文件,则代码不是 100% 可移植的。

你需要一种叫做序列化的东西。好的,计算机科学术语,但它基本上意味着您获取数据并将其转换为定义良好且记录在案的字节序列,稍后可以由相同或另一个程序将其读回内存。此字节序列与体系结构和平台无关。

大多数 Unix 环境已经带有XDR实现,它提供了数据序列化的例程。

一个简单的示例,将 4 编码为标准输出(您可以使用 shell 重定向,或使用 fopen() 打开文件而不是标准输出):

XDR xdrs;
double data[4] = { 1.0, 255.41, -357.1, 123.4 };
int i;

xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
for (i = 0; i < 4; i++)
    xdr_double(&xdrs, &data[i]);

现在,要(从标准输入)取回这些双打并打印它们:

XDR xdrs;
double data;
int i;

xdrstdio_create(&xdrs, stdin, XDR_DECODE);
for (i = 0; i < 4; i++) {
    xdr_double(&xdrs, &data);
    printf("%g\n", data);
}

您可以使用 XDR 对复杂结构进行编码和解码。这是向文件发送四个双精度的一种非常愚蠢的方式,通常您应该使用 xdr_array() 来读取/写入某些数据类型的数组。在保存和加载文件时,必须以相同的顺序执行相同的命令。事实上,您可以使用rpcgen自动生成 C 结构及其对应的 xdr 函数。

于 2010-06-15T19:29:08.307 回答
2

方法1应该有效。只需创建一个值为 1、2、...、10 的测试向量并将其发送过去。您可以读取创建的 ascii(因此您可以验证“导出”),因此还要检查重新读取文件的“导入”步骤。您可能会以这种方式失去精确度,但它应该让您操作起来。

方法 2 将在您使用处理不同字节顺序的库(例如 XDR)后起作用。这些事情曾经是“很久以前”的更大问题,并且有解决方案。这就是例如R之类的系统允许您在架构之间共享二进制文件的方式。

除非您在传输文件时做了一些非常尴尬的事情,否则不需要方法 3。

于 2010-06-15T16:26:16.993 回答
2

提供的细节很少。尽我所能回答。

..其中一个系统是IBM ppc997,另一个是AMD Opteron

以前的系统一般 (*) 使用 big-endian 表示,后来 - little-endian。读这个

(*) 这取决于操作系统。IBM 的 POWER CPU 可以同时进行小端和大端,但实际上在它们上运行的操作系统都没有使用小端模式。

通常,对于二进制表示,人们会选择一种字节序并与它一起进行二进制表示。对于网络东西,大端数字表示是一种规范。

这意味着所有做这样的事情的地方:

/* writing to binary */
int a = 1234;
write(fd,&a,sizeof(a));
/* reading from binary */
int x;
read(fd,&x,sizeof(x));

应该转换成这样的:

/* writing to binary */
int a = htonl(1234);
write(fd,&a,sizeof(a));
/* reading from binary */
int x;
read(fd,&x,sizeof(x));
x = ntohl(x);

另一种方法是将字节序指示符(例如,编写魔法并在另一边检查它:MAGIC = 0x12345678 v. MAGIC = 0x78563412)与二进制数据一起保存,并且仅在字节序不同时应用转换。尽管这种方法不太优雅,并且没有我所知道的真正优势。

于 2010-06-15T16:59:59.537 回答
0

解决方案 2 和 3 通常不起作用,因为不同的处理器可能使用不同的数字内部表示。对于整数,而不是浮点数/双精度数,您可以使用只处理不同机器的字节顺序的东西。浮点表示要复杂得多,您必须详细查找不同架构使用的表示。但是对于双精度而言,例如,对精度的要求只有最低限度,并且您可能会发现自己处于必须截断为两者的较小表示的情况。这些问题与您使用的操作系统(无论是否为 Unix)没有太大关系,而是与硬件如何拥有事物有关。

于 2010-06-15T16:42:18.513 回答
0

所有支持 IEEE 754 的处理器都对浮点数(技术上称为单数)和双数具有相同的二进制表示。唯一的区别在于处理器的字节顺序。

因此,IBM PPC 和 AMD Opteron 之间唯一的不兼容应该是双打的字节序。

当您将双打从磁盘字节交换到内存时,要这样做:

double swap(double a); // THIS IS NEVER THE RIGHT THING TO DO.

按值传入 double 可能会通过浮点寄存器传入。由于并非所有位组合都是有效的双精度,因此处理器可能会静默地将双精度转换为 NaN,它可能具有与传入的值不同的位表示。这更可能发生在具有相反端序的有效双精度. (有关更详细的说明,请参见此处。)

换句话说,将您想要字节交换的双精度作为指针或字符数组传递。(字符数组应该是最好的选择。)

于 2010-06-15T17:40:34.267 回答