内容


定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么

Comments

简介

要从大端编译器迁移到小端编译器,您可能需要更改一些代码,以便维持程序的行为或结果。在将代码从大端移植到小端时,应该考虑矢量、不同大小的项目之间的存储关联、16 位实数、复数和无格式数据文件等代码方面的差异。在 IBM Power Systems™ 上的小端 Linux® 版本使用了与大端版本不同的 ABI。此外,还需要更新对旧的 ABI 有依赖性的程序。新的内置函数使得针对矢量字节顺序的移植变得更容易。

本文将介绍在将用于 Power Systems 上的大端 IBM XL Fortran 的 Fortran 代码移植到 Power Systems 上的小端 IBM XL Fortran 时可能遇到的问题。本文对编码更改提出一些建议,还将介绍有助于移植代码的编译器特性和选项。

比较大端字节顺序和小端字节顺序

字节顺序决定了在内存中如何解释数据。平台的字节顺序由处理器的架构决定。目前使用的两种最常见的字节顺序类型是大端字节顺序和小端字节顺序。

在大端平台(在这篇文章中通常简称为大端)上,内存中的字节排序是最大的字节排在首位(或 “左边”)。在小端平台(在这篇文章中通常简称为小端)上,内存和矢量寄存器中的字节排序是最小的字节排在首位(或 “左边”)。

例如,图 1 描述了在大端和小端平台上的内存中如何存储 000102030405060716(可被解释为一个 8 字节的整数)。在图 1 中,a 表示在该位置的内存地址。

图 1:内存中的大端和小端字节顺序的表示

矢量

IBM POWER® 处理器架构支持包含 16 个 1 字节元素、8 个 2 字节元素、4 个 4 字节元素或者两个 8 字节元素的 16 字节矢量。该处理器拥有 128 位的矢量寄存器,还提供了指令来将矢量加载到寄存器,操作寄存器中的矢量,并将矢量寄存器存储到内存。IBM XL 编译器提供了使用矢量的内置函数和语言支持。

在​​矢量元素顺序方面,大端和小端之间存在差异。为了帮助处理这些差异,我们还引入了新的编译器选项和内置函数。下面的章节中将会解释这些差异和新特性。

矢量元素顺序和矢量元素字节顺序

在矢量寄存器中布置矢量元素的方式有两种。您可以从低到高加载元素,所以元素 0 是矢量寄存器中最左边的元素。另外,您也可以从高到低加载元素,使元素 0 是矢量寄存器中最右边的元素。前一种布置被称为 大端矢量元素顺序,而后者被称为 小端矢量元素顺序

在大端上,总是使用大端矢量元素顺序。

在小端上,您可以选择使用大端矢量元素顺序和小端矢量元素顺序。

不论采用哪一种矢量元素顺序,大端上的矢量元素都可以在内存中使用大端字节顺序。小端上的矢量元素默认情况下可以在内存中使用小端字节顺序。

为了说明大端和小端矢量元素顺序的差异,请看图 2 和图 3。

图 2 说明了如何在矢量寄存器中用大端矢量元素顺序表示 000102030405060708090A0B0C0D0E0F16(被解释为一个 16 字节的矢量)。图上的 b127 b0 标记分别表示寄存器的第 127 位和第 0 位。图中从上至下显示了用 1、2、4 和 8 字节的元素填充的矢量的表示。

图 2:矢量寄存器中的大端矢量元素顺序表示

图 3 描述了如何在矢量寄存器中用小端矢量元素顺序表示 000102030405060708090A0B0C0D0E0F16(被解释为一个 16 字节的矢量)。图上的 b127 b0 标记分别表示寄存器的第 127 位和第 0 位。图中从上至下显示了用 1、2、4 和 8 字节的元素填充的矢量的表示。

图 3:矢量寄存器中的小端矢量元素顺序表示

-qaltivec 选项

-qaltivec 选项可用来告诉小端编译器如何在矢量寄存器中对矢量元素进行排序。

如果 -qaltivec=le,编译器将按照小端元素顺序来加载矢量,并假定按小端元素顺序将矢量加载到矢量存储。如果需要的话,编译器会插入矢量排列操作,以确保该加载和存储的内部过程使用的是小端元素顺序。对于引用特定元素的矢量内部过程,编译器假定是按小端元素顺序来加载矢量的。在小端上,-qaltivec=le 是默认值。

如果 -qaltivec=be,编译器将按照大端元素顺序加载矢量,并假定按大端元素顺序将矢量加载到矢量存储。如果需要的话,编译器会插入矢量排列操作,以确保该加载和存储的内部过程使用的是大端元素顺序。对于引用特定元素的矢量内部过程,编译器假定是按大端元素顺序来加载矢量的。

为了说明这个问题,请考虑下面的程序:

       program main
         vector(integer(8)) v
         integer(8) i(2)
         equivalence(v, i)

         i = [z'0001020304050607', z'08090A0B0C0D0E0F']

         print 1, "First vector element:", vec_extract(v, 0)
         print 1, "Second vector element:", vec_extract(v, 1)
1        format(A, z16.16)
       end program

在大端平台上编译这个程序时,或者在小端平台上用 -qaltivec=le 编译它时,会产生以下输出:

First vector element:0001020304050607
Second vector element:08090A0B0C0D0E0F

但是,如果在一个小端平台上用 -qaltivec=be 编译该程序,则会产生以下输出:

First vector element:08090A0B0C0D0E0F
Second vector element:0001020304050607

矢量被反向 加载到矢量寄存器中,而数组 i 中的元素顺序保持不变。

更简单的矢量使用方法是,使用下一节中介绍的 vec_xlvec_xl_bevec_xstvec_xst_be 内部过程来进行加载和存储,而不是使用 EQUIVALENCE。请考虑下面的程序:

vector(real(4)) v1, v2, v3, v4
real(4) a(4)

v1 = vec_xl(0, [real(4) ::1.0, 2.0, 3.0, 4.0])
call vec_xst(v1, 0, a)
print *, 'v1=', a

v2 = vec_neg(v1)
call vec_xst(v2, 0, a)
print *, 'v2=', a

!Merge high and low depend on vector element order
v3 = vec_mergeh(v1, v2)
call vec_xst(v3, 0, a)
print *, 'v3=', a

v4 = vec_mergel(v1, v2)
call vec_xst(v4, 0, a)
print *, 'v4=', a

end

该程序在大端平台和小端平台上产生了相同的输出。输出是:

v1= 1.000000000 2.000000000 3.000000000 4.000000000
v2= -1.000000000 -2.000000000 -3.000000000 -4.000000000
v3= 1.000000000 -1.000000000 2.000000000 -2.000000000
v4= 3.000000000 -3.000000000 4.000000000 -4.000000000


矢量内部过程 vec_xlvec_xstvec_mergehvec_mergel 考虑了矢量元素顺序。换句话说,当在一个小端平台上用 -qaltivec=le 编译该程序时:

  • vec_xl 使用一个 Vector Scalar eXtension (VSX) 加载指令,该指令总是按大端元素顺序进行加载。然后,使用一个矢量排列指令来反转寄存器中的矢量,改用小端元素顺序。
  • vec_xst 假定在寄存器中的矢量使用小端矢量元素顺序,所以它使用一个矢量排列指令,将矢量元素反转为大端矢量元素顺序。然后,它使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。
  • vec_mergeh 知道矢量元素是从右侧开始的。矢量寄存器包含 v1 和 v2,如下所示:
v1	 4.0	 3.0	 2.0	 1.0
v2	-4.0	-3.0	-2.0	-1.0

因为 vec_mergeh 是从右侧开始算起的,它正确地使用 1.0 和 2.0 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。

  • vec_mergel 也同样知道矢量元素是从右侧开始的。因此,它正确地使用 -1.0 和 -2.0 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。

在大端平台或在小端平台上用 -qaltivec=be 编译该程序时:

  • vec_xl 使用了一个 VSX 加载指令,该指令总是按大端元素顺序进行加载。不需要矢量排列。
  • vec_xst 假定在寄存器中的矢量使用的是大端矢量元素顺序。因此,它直接使用一个 VSX 存储指令将矢量存储回内存中,该指令总是按大端元素顺序进行存储。
  • vec_mergeh 知道矢量元素是从左侧开始的。矢量寄存器包含 v1 和 v2,如下所示:
v1	 1.0	 2.0	 3.0	 4.0
v2	-1.0	-2.0	-3.0	-4.0

因为 vec_mergeh 是从左侧开始算起的,它正确地使用 1.0 和 2.0 作为 vec_mergeh(v1, v2) 的结果的元素 0 和 2。

vec_mergel 也同样知道矢量元素是从左侧开始的。因此,它正确地使用 -1.0 和 -2.0 作为 vec_mergel(v1, v2) 的结果的元素 1 和 3。

对于不使用 EQUIVALENCE 的程序,可以使用 –qaltivec=be 选项将代码从大端移植到小端。

POWER8 加密内部过程要求其输入矢量采用大端矢量元素顺序。实现这一要求有两种方法,使用 -qaltivec=be,或使用 vec_xl_bevec_xst_be 内部过程来加载和存储。这些矢量加载和存储函数将在下一部分中介绍。

新的矢量加载和存储内部过程

添加了新的矢量加载和存储内部过程,它们使用了 VSX 指令。您可以在 XL Fortran 编译器参考(XL Fortran for Linux 文档库)中找到这些内部过程。

VEC_XL(ARG1,ARG2)
这个函数从由位移 ARG1ARG2 的地址指定的内存地址加载一个 16 字节的矢量,使用与平台相应的元素顺序和 -qaltivec 选项。

ARG1 是一个 INTENT(IN) 整数。

ARG2 是以下任意类型的 INTENT(IN)

  • REAL(4)REAL(8)
  • INTEGER(1)INTEGER(2)INTEGER(4)INTEGER(8)
  • VECTOR

VEC_XL_BE(ARG1,ARG2)
这个函数从由位移 ARG1ARG2 的地址指定的内存地址加载一个 16 字节的矢量,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。

ARG1 是一个 INTENT(IN) 整数。

ARG2 是以下任意类型的 INTENT(IN)

  • REAL(4)REAL(8)
  • INTEGER(1)INTEGER(2)INTEGER(4)INTEGER(8)
  • VECTOR

VEC_XST(ARG1,ARG2,ARG3)
此函数将由 ARG1 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 ARG2 指定的位移添加到由 ARG3 指定的内存地址,使用与平台相应的元素顺序和 -qaltivec 选项。

ARG1 是一个 INTENT(IN) 矢量。

ARG2 是一个 INTENT(IN) 整数。

ARG3INTENT(OUT),并且必须是矢量或如下的整数或实数类型:

  • 如果 ARG3 是一个矢量,那么它必须与 ARG1 的类型相同。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个整数矢量或一个无符号矢量,那么 ARG3 必须是 INTEGER 类型,而且与 ARG1 的元素具有同一种类型的参数。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个实数矢量,那么 ARG3 必须与 ARG1 的元素具有相同的类型和种类。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个像素矢量,那么 ARG3 的类型必须是 INTEGER(2)

VEC_XST_BE(ARG1,ARG2,ARG3)
此函数将由 ARG1 指定的 16 字节矢量的元素存储到一个给定的内存地址中。该地址的计算方法是,将 ARG2 指定的位移添加到由 ARG3 指定的内存地址,无论在什么平台上,都使用大端顺序或 -qaltivec 选项。

ARG1 是一个 INTENT(IN) 矢量。

ARG2 是一个 INTENT(IN) 整数。

ARG3INTENT(OUT),而且必须是矢量或如下的整数或实数类型:

  • 如果 ARG3 是一个矢量,那么它必须与 ARG1 的类型相同。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个整数矢量或一个无符号矢量,那么 ARG3 必须是 INTEGER 类型,并且与 ARG1 的元素具有同一种类型的参数。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个实数矢量,那么 ARG3 必须与 ARG1 的元素具有相同的类型和种类。
  • 如果 ARG3 不是一个矢量,而且 ARG1 是一个像素矢量,那么 ARG3 的类型必须是 INTEGER(2)

应用程序二进制接口 (ABI)

面向小端 Linux on Power Systems 的 XL Fortran 使用了新的 IBM Power Architecture® 64 位 ELF V2 ABI 规范。这种新的 ABI 完善了某些方面,其中包括函数调用。不过,这意味着,针对旧 ABI 的程序集文件必须移植到新的 ABI。遵循各自的语言标准的 Fortran、C 和 C ++ 程序不需要移植到新的 ABI。包含非标准扩展的程序需要进行 ABI 敏感性审查。在 Fortran 中的一个例子是,程序调用带有变量参数列表的 C 函数。

从 Fortran 调用带有变量参数列表的 C 函数

C 语言允许函数带有变量参数列表。使用省略号(...)指示。例如,printf 有下面的 C 原型:

int printf(const char *restrict format, ...);

ELF V2 ABI 要求对带有变量参数列表的函数的调用者在堆栈上建立参数保存区域。因此,对带有变量参数列表的函数的调用必须有准确的原型。

然而,Fortran 标准将带有变量参数列表的 C 函数视为不可互操作的,在 Fortran 中没有为它们提供编写接口的方式。某些程序添加了一个显式接口(其中包含它们计划使用的最大数量的参数),试图解决这个问题。例如:

interface
  function printf1int(format, a) bind(c, name='printf')
    use, intrinsic :: iso_c_binding, only: c_int
    implicit none
    integer(c_int) printf1int
    character, intent(in) :: format(*)
    integer(c_int), value :: a
  end function
end interface

使用上述接口调用 printf1int 可能会由于缺少参数保存区而导致新 ABI 的堆栈损坏。要让 XL Fortran 知道变量参数列表,可以将 procedure_attribute(varargs) 指令添加到接口。

interface
  function printf1int(format, a) bind(c, name='printf')
    use, intrinsic :: iso_c_binding, only: c_int
    implicit none
    integer(c_int) printf1int
    character, intent(in) :: format(*)
    integer(c_int), value :: a
    !ibm* procedure_attribute(varargs)
  end function
end interface

不同大小的项目之间的存储关联

在将程序从大端移植到小端时,必须考虑不同大小的项目之间的存储关联。在 Fortran 中, 这涉及到 EQUIVALENCE、公共块、ENTRY 语句、参数关联,以及格式控制的 I/O。以下各小节将会更详细地介绍这些项目。

请注意,十六进制值始终按大端顺序进行打印。

EQUIVALENCE

Fortran 标准用 EQUIVALENCE 语句限制可以与存储关联在一起的对象的类型。但是,XL Fortran(和大多数编译器)允许几乎任何类型的对象出现在 EQUIVALENCE 中。当对不同大小的项目使用 EQUIVALENCE 时,小端和大端平台上的结果可能会有所不同。为了证明这一点,请考虑下面的程序:

       integer(8) j
       integer(4) i(2)
       integer(2) h(4)
       integer(1) k(8)
       equivalence (j, i), (j, h), (j, k)
       j = z'0001020304050607'
       print 1, 'j = ', j
       print 2, 'i = ', i
       print 4, 'h = ', h
       print 8, 'k = ', k
1      format(A, "z'", z16.16, "'")
2      format(A, 2("z'", z8.8, "'", 1x))
4      format(A, 4("z'", z4.4, "'", 1x))
8      format(A, 8("z'", z2.2, "'", 1x))
       end

在上述程序中,我们指定 jihk 共享存储空间,它们的种类各不相同。在大端和小端中,数组都是从左到右排列的,更准确地说,最低的数组元素具有最低的内存地址。每个数组元素的字节顺序在大端和小端上都是不一样的。在大端上,每个数组元素中最大的字节都位于左侧,所以 jihk 在内存中看起来是一样的。输出是:

j = z'0001020304050607'
i = z'00010203' z'04050607'
h = z'0001' z'0203' z'0405' z'0607'
k = z'00' z'01' z'02' z'03' z'04' z'05' z'06' z'07'

在小端平台上,每个数组元素中最小的字节都位于左侧,所以 jihk 在内存中看起来是不一样的。输出是:

j = z'0001020304050607'
i = z'04050607' z'00010203'
h = z'0607' z'0405' z'0203' z'0001'
k = z'07' z'06' z'05' z'04' z'03' z'02' z'01' z'00'

公共块

公共块提供了不同编译单元中的项目之间的存储关联。如果相同的公共块在两个编译单元中的声明不同,那么公共块成员是存储关联的。如果相应的成员具有不同的大小,当代码从大端移植到小端时需要有额外的考虑事项。请考虑下面的程序:

       subroutine sub1
         integer(8) j
         common /blk/ j
         j = z'0001020304050607'
         print 1, 'sub1:', j
1        format(A, "z'", z16.16, "'")
       end subroutine

       subroutine sub2
         integer(4) i(2)
         common /blk/ i
         print 2, 'sub2:', i
2        format(A, 2("z'", z8.8, "'", 1x))
       end subroutine

       program main
         call sub1
         call sub2
       end program

在上述代码中,ji 共享存储空间并具有不同的种类。该程序的输出显示 i 的元素在大端和在小端上的排序是不一样的。在大端上,运行程序产生以下输出:

sub1: z'0001020304050607'
sub2: z'00010203' z'04050607'

在小端上,运行程序产生以下输出:

sub1: z'0001020304050607'
sub2: z'04050607' z'00010203'

ENTRY 语句

当函数的结果有不同的特点时,函数的结果及其 ENTRY 语句之间的存储关联就会出现。在下面的程序中,fg 是存储关联的。

function f(a)
 double precision a, f
 real g
entry g(a)
 f = a
end function

program main
 interface
   function f(a)
     double precision a, f
   end function
   function g(a)
     double precision a
     real g
   end function
 end interface
 double precision x
 x = z'0001020304050607'
 print '(z16.16)', f(x)
 print '(z8.8)', g(x)
end program

在大端上,g是一个单精度实数,是双精度 f 最大的一半存储关联。因此,在大端上的输出为:

0001020304050607
00010203

在小端上,gf 最小的一半存储关联。因此,在小端上的输出为:

0001020304050607
04050607

参数关联

在 FORTRAN 77 样式中的调用没有使用显式接口,而是依靠用户传递正确的类型。在大端上,对于某些不符合要求的程序,虽然实际参数和伪参数不匹配,但仍然可以运行成功。请考虑下面的程序:

       program main
         integer :: i = 1
         character(5) :: c = 'abcd'
         integer(2) :: h = 2
         real(8) :: d = 1.0

         call hexprint(i, 4)
         call hexprint(c, 5)
         call hexprint(h, 2)
         call hexprint(d, 8)
       end program

       subroutine hexprint(buffer, size)
         character(8) buffer
         integer size
         print 100, buffer(1:size)

100      format (z<2 * size>.<2 * size>)
       end subroutine

该程序是不符合要求的,因为它将多种整数种类的实际参数与字符类型的伪参数关联。该程序没有使用显式接口,因此,编译器不会检测到错误。在大端上,字符和非字符数据使用了相同的字节顺序,因此,该程序产生了预期的输出。在小端上则不然。为了证明这一点,请看该程序在大端和小端上的输出。

在大端上,该程序产生以下输出:

00000001
6162636420
0002
3FF0000000000000

在小端上,该程序产生以下输出:

01000000
6162636420
0200
000000000000F03F

格式控制的 I/O

在格式控制的 I/O 中,用于读或写 I/O 项的编辑描述符必须与 I/O 项的类型和类型参数相对应。举例来说,如果 A 编辑描述符假定 I/O 项的类型为字符,但用来读或写整数类型的 I/O 项,那么有可能会出现移植问题。例如,请考虑下面的程序:

character(4) file
integer(4) a
a = z'61626364'
write(file, '(A)') a
print *, file
end

在大端上,输出为:
abcd

在小端上,输出为:
dcba

16 字节的实数和复数类型

XL Fortran 的扩展精度浮点型 REAL(16) 不是电气和电子工程师协会(IEEE)标准所建议的 binary128 格式。实际上,REAL(16) 包含两个 REAL(8) 部分,它们有不同的数量级,不会互相重叠(当数字是零或接近于零时除外)。即使在小端上,高阶 REAL(8) 值(即首先进入存储的)也必须有较大的数量级。REAL(16) 数字的值是它的两个 REAL(8) 部分的总和。

复数类型是由一个实数部分和一个虚数部分组成,其中实数部分始终在虚数部分之前。

请考虑以下代码片段:

real(8) d(2)
real(16) q
complex(8) z
equivalence (q, d), (q, z)
q = 1.0q0

在大端和小端上,d 的第一个元素都是 1.0d0,d 的第二个元素都是 0.0d0。复数 z 的实数部分是 1.0d0,虚数部分是 0.0d0。

16 字节实数和复数的元素字节顺序在大端和小端上是有所不同的,但元素顺序是相同的。

无格式数据文件

无格式 Fortran 数据文件由记录和记录标记组成。记录标记是 4 或 8 个字节的整数,包含在记录的字节数。记录标记出现在每条记录之前和之后。请看下面的示例。

write(10) 10, 11
end

该程序将以下数据(二进制)写入连接到单元 10 的文件中:

0x00000008 0x0000000a 0x0000000b 0x00000008

因为记录标记是整数,所以它们会受到字节顺序的影响。此外,由于上述的 10 和 11 是整数,它们也会受到字节顺序的影响。因此,对于使用了某种字节顺序(例如,大端)的无格式数据文件,必须经过转换才可以在一个使用不同的字节顺序(例如,小端)的平台上进行读取。XL Fortran 提供几种方法来执行转换。按优先级从高到低分别是:

  • XLFRTEOPTS=ufmt_bigendian=<units>XLFRTEOPTS=ufmt_littleendian=<units> 运行时选项
  • OPEN 语句中的 CONVERT= 指定符
  • @PROCESS UFMT 指令
  • -qufmt 编译器选项

下面各节会更详细地介绍这些方法。

运行时转换的环境变量

XLFRTEOPTS=xlf_bigendian=<units>XLFRTEOPTS=xlf_littleendian=<units> 环境变量可以用来在运行时指定需转换的无格式数据文件的字节顺序。

XLFRTEOPTS=xlf_bigendian=<units> 仅在小端上有效,并用于连接到大端无格式数据文件的单元。

XLFRTEOPTS=xlf_littleendian=<units> 仅在大端上有效,并用于连接到小端无格式数据文件的单元。

xlf_bigendianxlf_littleendian 均为 <units> 有效值的示例(以下示例显示 xlf_bigendian,但这些 <unit> 值也适用于 xlf_bigendian):

XLFRTEOPTS=xlf_bigendian=5
指定单元 5 连接到大端文件。

XLFRTEOPTS=xlf_bigendian=5-10
指定单元 5 至 10连接到大端文件。

XLFRTEOPTS=xlf_bigendian=1,5-10
指定单元 1 和 5 至 10 连接到大端文件。

XLFRTEOPTS=xlf_bigendian=1-
指定从 1 开始的所有单元连接到大端文件。

XLFRTEOPTS=xlf_bigendian=newunit
指定自动生成的所有单元连接到大端文件。自动生成的无格式单元在创建时带有负号。

XLFRTEOPTS=xlf_bigendian=1-,newunit XLFRTEOPTS=xlf_bigendian=*指定所有单元连接到大端文件。

在 OPEN 语句中的 CONVERT= 指定符

CONVERT= 指定符可以用来指定需转换的无格式数据文件的字节顺序。该指定符的有效值是:

CONVERT='NATIVE'
告诉编译器,该文件的字节顺序与本机平台相同,不需要转换。这是默认值。

CONVERT='BIG_ENDIAN'
告诉编译器,无格式文件使用大端字节顺序。在小端上,在对文件的双向数据传输操作上执行转换。在大端上,不需要执行转换。

CONVERT='BIG_ENDIAN'
告诉编译器,无格式文件使用小端字节顺序。在大端上,在对文件的双向数据传输操作上执行转换。在小端上,不需要执行转换。

源指令

@PROCESS UFMT 源指令适用于在编译单元中其前面出现的所有 OPEN 语句。

@PROCESS UFMT(big endian)
假定 OPEN 语句被连接到大端数据文件。在小端上,在运行时对这些文件的双向数据传输执行转换。在大端上,不需要执行转换。

@PROCESS UFMT(little endian)
假定 OPEN 语句被连接到小端数据文件。在大端上,在运行时对这些文件的双向数据传输执行转换。在小端上,不需要执行转换。

-qufmt 编译器选项

-qufmt 编译器选项允许用户指定在编译时要转换的无格式数据文件的字节顺序。

-qufmt=be
告诉编译器所有无格式数据文件都是大端。在小端上,在运行时对这些文件的双向数据传输执行转换。在大端上,不需要执行转换。

-qufmt=le
告诉编译器所有无格式数据文件都是小端。在大端上,在运行时对这些文件的双向数据传输执行转换。在小端上,不需要执行转换。

以反向字节顺序加载和存储

XL Fortran 提供了以下内部过程来帮助转换字节顺序:

LOAD2R(X)
以反向字节顺序加载 X 的值,其中 X 是一个类型为 INTEGER(2)INTENT(IN) 伪参数。结果的类型是 INTEGER(2)

LOAD4R(X)
以反向字节顺序加载 X 的值,其中 X 是一个类型为 INTEGER(4)INTENT(IN) 伪参数。结果的类型是 INTEGER(4)

LOAD8R(X)
以反向字节顺序加载 X 的值,其中 X 是一个类型为 INTEGER(8)INTENT(IN) 伪参数。结果的类型是 INTEGER(8)

REVERSE_BYTE_ORDER(X)
是一个泛型函数,以反向字节顺序加载 X 的值,其中 X 是一个类型为 INTEGER(2)INTEGER(4)INTEGER(8)INTENT(IN) 伪参数。它解析为 LOAD2RLOAD4RLOAD8R,具体情况取决于 X 的类型。其结果与 X 具有相同的类型和类型参数。

VEC_REVB(ARG1)
返回一个与 ARG1 相同类型的矢量,包含采用反向字节顺序的相应 ARG1 元素的字节。ARG1 是一个 INTENT(IN) 整数、无符号或实数矢量。

VEC_REVE(ARG1)
返回一个与 ARG1 相同类型的矢量,包含采用反向元素顺序的相应 ARG1 元素。ARG1 是一个 INTENT(IN) 整数、无符号或实数矢量。它返回一个与 X 相同类型的矢量,包含 INTENT(IN) 整数、无符号或实数矢量。

参考资料


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=996248
ArticleTitle=定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么
publish-date=01292015