arm大端小端方式 和小端方式 存取的结果有什么不同

developerWorks 社区
IBM(R) POWER8(TM) 平台支持使用大端或小端字节顺序的操作系统。在将为大端操作系统编写的程序迁移到小端操作系统时,可能需要更改代码,以便维持程序的行为或者结果。此外,还需要考虑矢量、不同大小的项目之间的存储关联、长双精度、复数和序列化等方面的差异。在 IBM XL C / C ++ 中为小端 Linux on Power Systems 实现的应用程序二进制接口(ABI)不同于在大端版本中实现的 ABI。我们添加了新的选项和内置函数来帮助移植。本文将介绍这些差异、新选项和内置函数,并对将代码移植到 POWER8 上的 IBM XL C / C ++ 需要做的代码更改提供了一些建议。
, 编译器验证专家,
Nicole Negherbon 是一名有 3 年经验的软件开发人员。Nicole 主要擅长的专业领域是 IBM AIX 和 Linux on POWER 上的 Fortran 语言编译器验证。Nicole 是运行 IBM AIX 和各种 Linux on Power 版本的 IBM POWER8 系统的系统管理员。
, 编译器软件开发人员,
Rafik Zurob 是一名有 13 年经验的咨询软件开发人员。Rafik 是 IBM AIX 和 Linux on POWER 上的 Fortran 编译器前端及运行时环境的团队主管。他是将 IBM C / C++ 和 Fortran 编译器产品迁移到 IBM Power 平台上的小端 Linux 的技术负责人。
, 编译器验证专家,
Nemanja Ivanovic 是一位高级软件开发人员,在 IBM Power Systems 和 Linux on System z 上的 C / C++ 编译器验证方面有 5 年的经验。Nemanja 已经在 IBM 加拿大实验室工作了 4 年,其主要专业知识领域是面向 AIX、Linux on POWER、Linux on OpenPower 和 Linux on System z 的 IBM XL C / C++ 编译器。
简介要从大端编译器迁移到小端编译器,您可能需要更改一些代码,以便维持程序的行为或结果。在将代码从大端移植到小端时,应该考虑矢量、不同大小的项目之间的存储关联、长双精度、复数和序列化等代码方面的差异。在 IBM Power Systems™ 上的小端 Linux® 版本使用了与大端版本不同的 ABI。此外,还需要更新对旧的 ABI 有依赖性的程序。新的内置函数使得针对矢量字节顺序的移植变得更容易。本文将介绍在将用于 Power Systems 上的大端 IBM XL C / C ++ 的代码移植到 Power Systems 上的小端 IBM XL C / C ++ 时可能遇到的问题。本文对编码更改提出一些建议,还将介绍有助于移植代码的编译器特性和选项。比较大端字节顺序和小端字节顺序字节顺序决定了在内存中如何解释数据。平台的字节顺序由处理器的架构决定。目前使用的两种最常见的字节顺序类型是大端字节顺序和小端字节顺序。在大端平台(在这篇文章中通常简称为大端)上,内存中的字节排序是最大的字节排在首位(或 “左边”)。在小端平台(在这篇文章中通常简称为小端)上,内存和矢量寄存器中的字节排序是最小的字节排在首位(或 “左边”)。例如,图 1 描述了在大端和小端平台上的内存中如何存储 060716(被解释为一个 8 字节的整数)。在图 1 中,a 表示在该位置的内存地址。图 1:内存中的大端和小端字节顺序的表示矢量IBM POWER® 处理器架构支持包含 16 个 1 字节元素、8 个 2 字节元素、4 个 4 字节元素或者两个 8 字节元素的 16 字节矢量。该处理器拥有 128 位的矢量寄存器,还提供了指令来将矢量加载到寄存器,操作寄存器中的矢量,并将矢量寄存器存储到内存。IBM XL 编译器提供了使用矢量的内置函数和语言支持。在矢量元素顺序方面,大端和小端之间存在差异。为了帮助处理这些差异,我们还引入了新的编译器选项和内置函数。下面的章节中将会解释这些差异和新特性。矢量元素顺序和矢量元素字节顺序在矢量寄存器中布置矢量元素的方式有两种。您可以从低到高加载元素,所以元素 0 是矢量寄存器中最左边的元素。此外,您还可以从高到低加载元素,让元素 0 成为矢量寄存器中最右边的元素。前一种布置被称为大端矢量元素顺序,后一种布置被称为小端矢量元素顺序。在大端上,总是使用大端矢量元素顺序。在小端上,您可以选择使用大端矢量元素顺序和小端矢量元素顺序。不论采用哪一种矢量元素顺序,大端上的矢量元素都可以在内存中使用大端字节顺序。小端上的矢量元素默认情况下可以在内存中使用小端字节顺序。为了说明大端和小端矢量元素顺序的差异,请参见图 2 和图 3。图 2 说明了如何在矢量寄存器中用大端矢量元素顺序表示 B0C0D0E0F16(被解释为一个 16 字节的矢量)。图上的 b127 和 b0
标记分别表示寄存器的第 127 位和第 0 位。图中从上至下显示了用 1、2、4 和 8 字节的元素填充的矢量的表示。图 2:矢量寄存器中的大端矢量元素顺序表示 图 3 描述了如何在矢量寄存器中用小端矢量元素顺序表示 B0C0D0E0F16(被解释为一个 16 字节的矢量)。图上的 b127 和 b0
标记分别表示寄存器的第 127 位和第 0 位。图中从上至下显示了用 1、2、4 和 8 字节的元素填充的矢量的表示。图 3:矢量寄存器中的小端矢量元素顺序表示-qaltivec 选项-qaltivec 选项可用来告诉小端编译器如何在矢量寄存器中对矢量元素进行排序。如果 -qaltivec=le,那么编译器将按照小端元素顺序来加载矢量,并假定按小端元素顺序将矢量加载到矢量存储。如果需要的话,编译器会插入矢量排列操作,以确保该加载和存储的内置函数使用的是小端元素顺序。对于引用特定元素的矢量内置函数,编译器假定是按小端元素顺序来加载矢量的。在小端上,-qaltivec=le 是默认值。如果 -qaltivec=be,那么编译器将按照大端元素顺序来加载矢量,并假定按大端元素顺序将矢量加载到矢量存储。如果需要的话,编译器会插入矢量排列操作,以确保该加载和存储的内置函数使用的是大端元素顺序。对于引用特定元素的矢量内置函数,编译器假定是按大端元素顺序来加载矢量的。为了说明这个问题,请考虑下面的程序:#include&stdio.h&
union Example
int sint[4];
int main() {
example.sint[0] = 0x0102;
example.sint[1] = 0x0304;
example.sint[2] = 0x0506;
example.sint[3] = 0x0708;
printf("First vector element:%04x\n", vec_extract(example.vint,0));
printf("Second vector element:%04x\n", vec_extract(example.vint,1));
printf("Third vector element:%04x\n", vec_extract(example.vint,2));
printf("Fourth vector element:%04x\n", vec_extract(example.vint,3));
}在大端平台上编译这个程序时,或者在小端平台上用 -qaltivec=le 编译它时,会产生以下输出:First vector element:0102
Second vector element:0304
Third vector element:0506
Fourth vector element:0708但是,如果在一个小端平台上使用 -qaltivec=be 编译该程序,则会产生以下输出:First vector element:0708
Second vector element:0506
Third vector element:0304
Fourth vector element:0102矢量被反向 加载到矢量寄存器中,而数组 i 中的元素顺序保持不变。更简单的矢量使用方法是,使用下一节中介绍的 vec_xl、vec_xl_be、vec_xst 和 vec_xst_be 内置函数来进行加载和存储。请考虑下面的程序:#include&stdio.h&
int main() {
vector signed int v1;
vector signed int v2;
vector signed int v3;
vector signed int v4;
v1 = vec_xl(0, (int[]){1,2,3,4});
vec_xst(v1, 0, a);
printf("v1 via a:%d %d %d %d\n", a[0],a[1],a[2],a[3]);
v2 = vec_neg(v1);
vec_xst(v2, 0, a);
printf("v2 via a:%d %d %d %d\n", a[0],a[1],a[2],a[3]);
//Merge high and low depend on vector element order
v3 = vec_mergeh(v1, v2);
vec_xst(v3, 0, a);
printf("v3 via a:%d %d %d %d\n", a[0],a[1],a[2],a[3]);
v4 = vec_mergel(v1, v2);
vec_xst(v4, 0, a);
printf("v4 via a:%d %d %d %d\n", a[0],a[1],a[2],a[3]);
}该程序在大端平台和小端平台上产生了相同的输出。输出是:v1 via a:1 2 3 4
v2 via a:-1 -2 -3 -4
v3 via a:1 -1 2 -2
v4 via a:3 -3 4 -4矢量内置函数 vec_xl、vec_xst、vec_mergeh 和 vec_mergel 考虑了矢量元素顺序。换句话说,当在一个小端平台上用 -qaltivec=le 编译该程序时:vec_xl 使用一个 Vector Scalar eXtension (VSX) 加载指令,该指令总是按大端元素顺序进行加载。然后,使用一个矢量排列指令来反转寄存器中的矢量,改用小端元素顺序。vec_xst 假定在寄存器中的矢量使用了小端矢量元素顺序,所以它使用一个矢量排列指令,将矢量元素反转为大端矢量元素顺序。然后,它使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。vec_mergeh 知道矢量元素是从右侧开始的。矢量寄存器包含 v1 和 v2,如下所示:v1
v2 -4 -3 -2 -1因为 vec_mergeh 是从右侧开始算起的,它正确地使用 1 和 2 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。vec_mergel 也同样知道矢量元素是从右侧开始的。因此,它正确地使用 -1 和 -2 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。在大端平台或在小端平台上用 -qaltivec=be 编译该程序时:vec_xl 使用了一个 VSX 加载指令,该指令总是按大端元素顺序进行加载。不需要矢量排列。vec_xst 假定在寄存器中的矢量使用的是大端矢量元素顺序。因此,它直接使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。vec_mergeh 知道矢量元素是从左侧开始的。矢量寄存器包含 v1 和 v2,如下所示:v1
v2 -1 -2 -3 -4因为 vec_mergeh 是从左侧开始算起的,所以它正确地使用 1 和 2 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。vec_mergel 也同样知道矢量元素是从左侧开始的。因此,它正确地使用 -1 和 -2 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。对于没有使用联合的程序,可以使用 –qaltivec=be 选项将代码从大端移植到小端。POWER8 加密内置函数要求其输入矢量采用大端矢量元素顺序。实现这一要求有两种方法,使用 -qaltivec=be,或者使用 vec_xl_be 和 vec_xst_be 函数来加载和存储。这些矢量加载和存储函数将在下一部分中进行介绍。新的矢量加载和存储内置函数添加了新的矢量加载和存储内置函数,它们使用了 VSX 指令。请注意,面向小端 Linux on Power Systems 的 XL C/C++ 是一个 64 位编译器产品,所以只适用 64 模式的原型。在 XL C/C++ 编译器参考()中详述了这些内置函数。vec_xl(offset, address)这个函数从由位移 offset 和 address 的地址指定的内存地址加载一个 16 字节的矢量,使用与平台相应的元素顺序和 -qaltivec 选项。原型(64 位模式):vector signed char vec_xl(long, signed char *);
vector unsigned char vec_xl(long, unsigned char *);
vector signed short vec_xl(long, signed short *);
vector unsigned short vec_xl(long, unsigned short *);
vector signed int vec_xl(long, signed int *);
vector unsigned int vec_xl(long, unsigned int *);
vector signed long long vec_xl(long, signed long long *);
vector unsigned long long vec_xl(long, unsigned long long *);
vector float vec_xl(long, float *);
vector double vec_xl(long, double *);vec_xl_be(offset, address)这个函数从由位移 offset 和 address 的地址指定的内存地址加载一个 16 字节的矢量,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。原型(64 位模式):vector signed char vec_xl_be(long, signed char *);
vector unsigned char vec_xl_be(long, unsigned char *);
vector signed short vec_xl_be(long, signed short *);
vector unsigned short vec_xl_be(long, unsigned short *);
vector signed int vec_xl_be(long, signed int *);
vector unsigned int vec_xl_be(long, unsigned int *);
vector signed long long vec_xl_be(long, signed long long *);
vector unsigned long long vec_xl_be(long, unsigned long long *);
vector float vec_xl_be(long, float *);
vector double vec_xl_be(long, double *);vec_xst(vect, offset, address)此函数将由 vect 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 offset 指定的位移添加到由 address 指定的内存地址,使用与平台相对应的元素顺序和 -qaltivec 选项。原型(64 位模式):void vec_xst(vector signed char, long, signed char *);
void vec_xst(vector unsigned char, long, unsigned char *);
void vec_xst(vector signed short, long, signed short *);
void vec_xst(vector unsigned short, long, unsigned short *);
void vec_xst(vector signed int, long, signed int *);
void vec_xst(vector unsigned int, long, unsigned int *);
void vec_xst(vector signed long long, long, signed long long *);
void vec_xst(vector unsigned long long, long, unsigned long long *);
void vec_xst(vector float, long, float *);
void vec_xst(vector double, long, double *);vec_xst_be(vect, offset, address)此函数将由 vect 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 offset 指定的位移添加到由 address 指定的内存地址,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。原型(64 位模式):void vec_xst_be(vector signed char, long, signed char *);
void vec_xst_be(vector unsigned char, long, unsigned char *);
void vec_xst_be(vector signed short, long, signed short *);
void vec_xst_be(vector unsigned short, long, unsigned short *);
void vec_xst_be(vector signed int, long, signed int *);
void vec_xst_be(vector unsigned int, long, unsigned int *);
void vec_xst_be(vector signed long long, long, signed long long *);
void vec_xst_be(vector unsigned long long, long, unsigned long long *);
void vec_xst_be(vector float, long, float *);
void vec_xst_be(vector double, long, double *);矢量文字和二进制编码的十进制 (BCD)二进制编码的十进制 (BCD) 内置函数对在矢量寄存器中加载的带符号 BCD 值进行运算。每个 BCD 由一系列 4 字节半字节(nibbles)组成,其中含 0 至 9 中的一个值,并且最后一个半字节包含符号。例如,值 10 (在 4 字节半字节中)被表示为:0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0xC上述每个十六进制值表示一个 4 字节半字节。0x1 半字节代表 10 中的 1,其后的 0x0 半字节表示 10 中的0。0xC 半字节是一个特殊的值,它代表一个加号。因为没有 BCD 数据类型和 BCD 数字需要加载到矢量寄存器中,所以 BCD 内置函数使用了 vector unsigned char 参数和结果。这使得即使 BCD 数字本身并不是矢量,BCD 内置函数也要依赖于矢量元素顺序。换句话说,即使使用 –qaltivec=le 编译,也需要按大端矢量元素顺序加载含有 BCD 数字的矢量。当矢量被静态初始化(例如,使用矢量文字)时,这是一个问题:括号内含有按大端顺序列出的字节元素的静态矢量初始化表达式在小端平台上会按小端元素顺序填充矢量寄存器。要解决这个问题,可以反转矢量初始化中的元素顺序。例如,请考虑下面的程序:#include &stdio.h&
#if __LITTLE_ENDIAN__
#define BCD_INIT(b0, b1, b2, b3, b4, b5, b6, b7, \
b8, b9, ba, bb, bc, bd, be, bf) \
{ bf, be, bd, bc, bb, ba, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0 }
#define BCD_INIT(b0, b1, b2, b3, b4, b5, b6, b7, \
b8, b9, ba, bb, bc, bd, be, bf) \
{ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf }
vector unsigned char v1001 =
BCD_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1C);
vector unsigned char v9009 =
BCD_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x9C);
static void print_bytes(vector unsigned char v)
unsigned char b[16];
vec_xst_be(v, 0, b);
printf("%.02hhx", b[0]);
for (i = 1; i & 16; ++i)
printf(", %.02hhx", b[i]);
printf("\n");
int main(void)
printf("Adding statically initialized vectors\n");
printf("op1 is
print_bytes(v1001);
printf("op2 is
print_bytes(v9009);
result = __bcdadd(v1001, v9009, 0);
printf("result is ");
print_bytes(result);
}该程序将在大端和小端平台上打印下面的数据。Adding statically initialized vectors
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 10, 00, 1c
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 90, 00, 9c
result is 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, 00, 01, 0c只在小端平台上预定义 __LITTLE_ENDIAN__ 宏。我们创建了一个 BCD_INIT 宏,以便反转初始化中的字节。请注意,print_bytes 函数使用了 vec_xst_be 内置函数,因为矢量是按大端矢量元素顺序进行排列的。其他解决方法将在运行时使用 vec_xl_be 内置函数进行初始化,或在运行时使用 vec_reve 内置函数反转静态初始化的矢量的矢量元素顺序。应用程序二进制接口 (ABI)面向小端 Linux on Power Systems 的 XL C/C++ 使用了新的 。这种新的 ABI 完善了几个方面,包括函数调用。然而,这意味着,针对旧 ABI 的程序集文件必须移植到新的 ABI。遵循各自的语言标准的 Fortran、C 和 C ++ 程序不需要移植到新的 ABI。包含非标准扩展的程序需要进行 ABI 敏感性审查。不同大小的项目之间的存储关联在将程序从大端移植到小端时,必须考虑不同大小的项目之间的存储关联。在 C / C ++ 中,这涉及到联合与指针转型。以下各节将会更详细地概述这些内容。请注意,十六进制值始终按大端顺序进行打印。联合当使用不同大小的项目的联合时,在小端和大端平台上的结果可能会有所不同。为了证明这一点,请考虑下面的程序:#include&stdio.h&
union Example
example.k = 0x;
printf("example.i:%02x\n", example.i);
printf("example.j:%04x\n", example.j);
printf("example.k:%08x\n", example.k);
}在上述程序中,我们已指定 i、j 和 k 共享存储空间 – 它们的大小全都不同。在大端上,最大的字节放在最低的内存地址(或左侧)中,所以 i、j 和 k 包含以下数据:example.i:01
example.j:0102
example.k:在小端上,最小的字节放在左侧,所以 i、j 和 k 包含以下数据:example.i:04
example.j:0304
example.k:指针转型指针转型的问题与那些由联合引入的问题其实是一样的。请考虑下面的程序:#include&stdio.h&
int main() {
int i = 0x;
printf("example.i:%02x\n", *(char*)&i);
printf("example.j:%04x\n", *(short*)&i);
printf("example.k:%08x\n", *(int*)&i);
}请注意,如果更改语言的规则,那么该代码将是无效(例如,不能将 integer 作为 short 来处理),不过,该代码简单地说明了这一问题。在上面的程序中,指针转型被用于将 i 转型为 char、short 和 int。在大端上,i 的最大字节在最低的内存地址中。该程序在大端上的输出如下所示:example.i:01
example.j:0102
example.k:在小端上,i 的最小字节在最低的内存地址中。该程序在小端上的输出如下所示:example.i:04
example.j:0304
example.k:长双精度和复数类型XL C/C++ 的长双精度类型包含两部分双精度,它们使用不同的数量级,不会重叠(只有当数字是零或接近零时除外)。即使在小端上,高阶双精度(即首先进入存储的)也必须有较大的数量级。长双精度数字的值是它的两个实数部分的总和。复数类型由一个实数部分和一个虚数部分组成,实数部分始终在虚数部分之前。在 C/C++ 中,您可以使用 __real__ 和 __imag__ 一元运算符或 creal 和 cimag 函数集来访问实数部分和虚数部分。请考虑下面的程序:#include&stdio.h&
#include&complex.h&
union Example
float f[2];
int main()
example.c = 1.0f + 0.0f*I;
printf("First element of float:%.4f\n", example.f[0]);
printf("Second element of float:%.4f\n", example.f[1]);
printf("Real part of complex:%.4f\n", __real__(example.c));
printf("Imaginary part of complex:%.4fi\n", __imag__(example.c));
}在大端和小端上,f 的第一个元素都是 1.0000,f 的第二个元素都是
0.0000。复数 c 的实数部分是 1.0000,虚数部分是 0.0000i。First element of float:1.0000
Second element of float:0.0000
Real part of complex:1.0000
Imaginary part of complex:0.0000i浮点和复数的元素字节顺序在大端和小端上是有所不同的,但元素顺序是相同的。序列化二进制数据文件依赖于数据的字节顺序。如果在大端平台上生成了一个二进制数据文件,那么在小端平台上读取文件时,需要转换数据的字节顺序。可以使用 __load2r、__load4r、__load8r、__store2r、__store4r 和 __store8r 内置函数来转换字节顺序。例如,当下面的程序在一个大端平台上编译和运行时,就会产生一个二进制文件 bigendian.data:$ cat writefile.c
#include &stdlib.h&
#include &stdio.h&
#include "data.h"
int main() {
data_t data = { {1,2,3,4,5,6,7,8}, {1,2,3,4}, {-1,-2}, 3.0, 4.0, "abcdefgh" };
fp = fopen("bigendian.data", "w");
if (fp == NULL) {
perror("fopen");
res = fwrite(&data, sizeof(data), 1, fp);
if (res != 1) {
perror("fwrite");
fclose(fp);
printf("Wrote:\n");
print_data(data);
$ cat data.h
#ifndef DATA_H
#define DATA_H
#include &stdint.h&
typedef struct {
int64_t ll[8];
int32_t i[4];
int16_t s[2];
char c[10];
static void print_data(data_t data) {
printf("data: ll={ ");
for (i = 0; i & 8; ++i) {
printf("0x%016lx ", data.ll[i]);
printf("}\n");
for (i = 0; i & 4; ++i) {
printf("0x%08x ", data.i[i]);
printf("}\n");
for (i = 0; i & 2; ++i) {
printf("0x%04hx ", data.s[i]);
printf("}\n");
f=%f\n", data.f);
d=%f\n", data.d);
while(i & 10 && data.c[i] != '\0') {
printf("%c", data.c[i]);
printf("\n");
#endiffwrite 将数据写入为字节流。因此,ll、i、s、f 和 d 将会采用大端字节顺序。为了在小端平台上读取文件,读取例程不能只使用 fread。它还需要转换数据。例如:$ cat readfile.c
#include &stdlib.h&
#include &stdio.h&
#include &stdint.h&
#include "data.h"
static void print_data(data_t data);
int main() {
fp = fopen("bigendian.data", "r");
if (fp == NULL) {
perror("fopen");
/* This fread call will read all non-character data
in the wrong byte order */
res = fread(&data, sizeof(data), 1, fp);
if (res != 1) {
perror("fread");
printf("Read:\n");
print_data(data);
/* Convert the byte order */
uint64_t u64;
uint32_t u32;
/* convert the long long data */
for (i = 0; i & 8; ++i) {
data.ll[i] = __load8r((uint64_t *) &data.ll[i]);
/* convert the integer data */
for (i = 0; i & 4; ++i) {
data.i[i] = __load4r((uint32_t *) &data.i[i]);
/* convert the short data */
for (i = 0; i & 2; ++i) {
data.s[i] = __load2r((uint16_t *) &data.s[i]);
/* convert the float data */
tmp.f = data.f;
__store4r(tmp.u32, &data.f);
/* convert the double data */
tmp.d = data.d;
__store8r(tmp.u64, &data.d);
printf("After conversion:\n");
print_data(data);
}当在小端平台上编译和运行 readfile.c 时,生成以下输出。Read:
data: ll={ 0x0 0x0
i={ 0xxxx }
s={ 0xffff 0xfeff }
f=0.000000
d=0.000000
c=abcdefgh
After conversion:
data: ll={ 0x2 0x4
i={ 0xxxx }
s={ 0xffff 0xfffe }
f=3.000000
d=4.000000
c=abcdefgh当移植依赖于数据的字节顺序的算法时,也需要有类似的考虑。例如,一个函数读取一个包含任意长度的十六进制字符串的文本文件,并将其转换成一个数组 uint64_t,该函数可以将字符串转型为 uint64_t *。虽然这违反了 ANSI 别名规则,但它适用于大端平台,因为 char[8] 数组和 uint64_t 的字节顺序是相匹配的。在小端平台上则不然。以反向字节顺序进行加载和存储XL C/C++ 提供以下内置函数来帮助转换字节顺序:unsigned short __load2r(unsigned short* address)用反向字节顺序从 address 加载一个无符号的 short。unsigned int __load4r(unsigned int* address) 用反向字节顺序从 address 加载一个无符号的整数。unsigned long long __load8r(unsigned long long* address)用反向字节顺序从 address 加载一个无符号的 long long。void __store2r(unsigned short source, unsigned short* address) 用反向字节顺序将一个无符号的 short source
存储到 address。void __store4r(unsigned int source, unsigned int* address) 用反向字节顺序将一个无符号的整数 source
存储到 address。void __store8r(unsigned long long source, unsigned long long* address)用反向字节顺序将一个无符号的 long long source
存储到 address。vec_revb(address)返回一个与 address 类型相同的矢量,包含采用反向字节顺序的相应 address 元素的字节。原型:vector signed char vec_revb(vector signed char);
vector unsigned char vec_revb(vector unsigned char);
vector signed short vec_revb(vector signed short);
vector unsigned short vec_revb(vector unsigned short);
vector signed int vec_revb(vector signed int);
vector unsigned int vec_revb(vector unsigned int);
vector signed long long vec_revb(vector signed long long);
vector unsigned long long vec_revb(vector unsigned long long);
vector float vec_revb(vector float)
vector double vec_revb(vector double);vec_reve(address)返回一个与 address 类型相同的矢量,包含采用反向元素顺序的 address 元素。原型:vector signed char vec_reve(vector signed char);
vector unsigned char vec_reve(vector unsigned char);
vector signed short vec_reve(vector signed short);
vector unsigned short vec_reve(vector unsigned short);
vector signed int vec_reve(vector signed int);
vector unsigned int vec_reve(vector unsigned int);
vector signed long long vec_reve(vector signed long long);
vector unsigned long long vec_reve(vector unsigned long long);
vector float vec_reve(vector float);
vector double vec_reve(vector double);参考资料访问
产品页面,了解有关的更多信息。访问 ,了解有关的更多信息。获得 XL C/C++ for Linux 的 。保持联系。加入 Rational
社区。访问 developerWorks ,了解关于信息管理的更多信息,获取技术文档、how-to 文章、培训、下载、产品信息以及其他资源。加入 。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=LinuxArticleID=995850ArticleTitle=定位您的应用程序 - 小端和大端 IBM XL C / C++ 编译器的差异对您意味着什么publish-date=

我要回帖

更多关于 大端模式和小端模式 的文章

 

随机推荐