字节序

定义

字节序,即一个多字节的数据在内存中存储方式。计算机领域中,主要有两种字节序,即小端序(little endian)和大端序(big endian)。

举例说明,假设一个整型变量占四个字节,其十六进制表示为 0x01234567,首地址为 0x101,则该整型变量的四个字节将被存储在内存 0x101-0x104 中。若按照大端序存储,则 01 位于地址 0x10023 位于地址 0x101,以此类推。而小端序则是 67 位于地址 0x10045 位于 0x101。直观的来看,大端序即数据的最高字节在地址上更靠前,小端序则是数据的最低字节在地址上更靠前。关于字节序的详细说明,请参考维基百科相关条目。

麻烦

不同的处理器可能使用不同的字节序,这在数据交换的时候会带来很多麻烦。

比如用一个大端序的机器将数据 0x01234567 写入文件中,然后将文件复制到一个小端序的机器中,小端序机器在读取数据时会顺序读取,即将 01 放入低地址位,将 67 放在高地址位,而在解释时会认为低地址位的是最低字节。所以,大端序的 0x1234567 会被小字节序当做 0x67452301。通常在不同字节序的机器间传输数据时都需要先进行字节序的转换。

字节序的判断

大多数个人计算机的字节序都是小端序,可以通过下面的命令查看当前机器的字节序:

$ lscpu | grep -i byte

对于 SAC 文件来说,由于 SAC 头段中并没有包含当前字节序的相关信息,所以 SAC 只能通过当前文件的 SAC 版本号,即 nvhdr 来判断。若 nvhdr 的值在0到6之间,则 SAC 文件的字节序与当前机器字节序相同,否则不同则需要做字节序转换。

如果想自己确认数据与机器的字节序是否相同,可以用如下命令查看:

$ od -j304 -N4 -An -td file.SAC

该命令会输出 SAC 文件中的第305到308字节,若输出为 6 则表示文件字节序与当前机器字节序相同,否则不同。

字节序的转换

SAC 程序在读入数据时,会自动检测当前机器的字节序以及当前数据的字节序。若二者不相同,则会对已读入内存中的数据进行字节序的转换。

但 SAC 相关的工具却不一定可以。比如,旧版本的 saclst 以及网上的某些 matlab 处理脚本大多是没有对 SAC 文件的字节序做判断的。这会导致一个让人困惑的问题:数据用 SAC 读取和查看一切正常,但是用其他工具读却乱七八糟,数据点数、采样间隔以及具体的数据值没有一个对的。这种问题很多情况下都是因为字节序导致的。

如果 SAC 文件的字节序跟当前机器的字节序不同,最好将 SAC 文件转换到当前机器的字节序,这样不论是 SAC 还是其他工具都可以正常对数据进行处理。字节序转换的办法很简单:

SAC> r *.SAC
SAC> w over

直接将所有 SAC 数据读入 SAC,然后再 w over 即可,SAC 会自动以当前机器的字节序覆盖磁盘中的文件。