定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么(3)
- UID
- 1066743
|
定位您的应用程序 - 小端和大端 IBM XL Fortran 编译器的差异对您意味着什么(3)
不同大小的项目之间的存储关联在将程序从大端移植到小端时,必须考虑不同大小的项目之间的存储关联。在 Fortran 中, 这涉及到 EQUIVALENCE、公共块、ENTRY 语句、参数关联,以及格式控制的 I/O。以下各小节将会更详细地介绍这些项目。
请注意,十六进制值始终按大端顺序进行打印。
EQUIVALENCEFortran 标准用 EQUIVALENCE 语句限制可以与存储关联在一起的对象的类型。但是,XL Fortran(和大多数编译器)允许几乎任何类型的对象出现在 EQUIVALENCE 中。当对不同大小的项目使用 EQUIVALENCE 时,小端和大端平台上的结果可能会有所不同。为了证明这一点,请考虑下面的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 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
|
在上述程序中,我们指定 j 与 i、h 和 k 共享存储空间,它们的种类各不相同。在大端和小端中,数组都是从左到右排列的,更准确地说,最低的数组元素具有最低的内存地址。每个数组元素的字节顺序在大端和小端上都是不一样的。在大端上,每个数组元素中最大的字节都位于左侧,所以 j、i、h 和 k 在内存中看起来是一样的。输出是:
1
2
3
4
| 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'
|
在小端平台上,每个数组元素中最小的字节都位于左侧,所以 j、i、h 和 k 在内存中看起来是不一样的。输出是:
1
2
3
4
| 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'
|
公共块公共块提供了不同编译单元中的项目之间的存储关联。如果相同的公共块在两个编译单元中的声明不同,那么公共块成员是存储关联的。如果相应的成员具有不同的大小,当代码从大端移植到小端时需要有额外的考虑事项。请考虑下面的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| 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
|
在上述代码中,j 和 i 共享存储空间并具有不同的种类。该程序的输出显示 i 的元素在大端和在小端上的排序是不一样的。在大端上,运行程序产生以下输出:
1
2
| sub1: z'0001020304050607'
sub2: z'00010203' z'04050607'
|
在小端上,运行程序产生以下输出:
1
2
| sub1: z'0001020304050607'
sub2: z'04050607' z'00010203'
|
ENTRY 语句当函数的结果有不同的特点时,函数的结果及其 ENTRY 语句之间的存储关联就会出现。在下面的程序中,f 和 g 是存储关联的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| 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 最大的一半存储关联。因此,在大端上的输出为:
1
2
| 0001020304050607
00010203
|
在小端上,g与 f 最小的一半存储关联。因此,在小端上的输出为:
1
2
| 0001020304050607
04050607
|
参数关联在 FORTRAN 77 样式中的调用没有使用显式接口,而是依靠用户传递正确的类型。在大端上,对于某些不符合要求的程序,虽然实际参数和伪参数不匹配,但仍然可以运行成功。请考虑下面的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| 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
|
该程序是不符合要求的,因为它将多种整数种类的实际参数与字符类型的伪参数关联。该程序没有使用显式接口,因此,编译器不会检测到错误。在大端上,字符和非字符数据使用了相同的字节顺序,因此,该程序产生了预期的输出。在小端上则不然。为了证明这一点,请看该程序在大端和小端上的输出。
在大端上,该程序产生以下输出:
1
2
3
4
| 00000001
6162636420
0002
3FF0000000000000
|
在小端上,该程序产生以下输出:
1
2
3
4
| 01000000
6162636420
0200
000000000000F03F
|
格式控制的 I/O在格式控制的 I/O 中,用于读或写 I/O 项的编辑描述符必须与 I/O 项的类型和类型参数相对应。举例来说,如果 A 编辑描述符假定 I/O 项的类型为字符,但用来读或写整数类型的 I/O 项,那么有可能会出现移植问题。例如,请考虑下面的程序:
1
2
3
4
5
6
| character(4) file
integer(4) a
a = z'61626364'
write(file, '(A)') a
print *, file
end
|
在大端上,输出为:
abcd
在小端上,输出为:
dcba |
|
|
|
|
|