Fortran 中不同类型整数之间的转换规则是什么?
What are the rules surrounding conversion between different kinds of integers in Fortran?
考虑以下代码片段:
integer(int8) :: a
integer(int32) :: b
integer(int64) :: c
a = - huge(a) - 1
b = - huge(b) - 1
c = - huge(c) - 1
print *, a, b, c
a = int(b, kind=int8)
c = int(b, kind=int64)
print *, a, b, c
在我的系统上它给出了以下输出:
-128 -2147483648 -9223372036854775808
0 -2147483648 -2147483648
这表明不同种类整数之间的转换发生如下:
- 扩大整数转换[更少的字节到更多的字节]是通过符号扩展完成的。
- 缩小整数转换[更多字节到更少字节]是通过简单地去掉高阶位来完成的。
这类似于Java的整数转换规则。
行为是否定义为标准 Fortran?有什么方法可以覆盖规则 1 并简单地获得正常的加宽 [比如 Java 的 Integer.toUnsignedLong()]?
编译器信息:
GNU Fortran (Rev6, Built by MSYS2 project) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
在F2018的10.2.1.3(8)你会发现内在赋值右边表达式的值是按照一个table转换的。当分配给整数的变量时,INT()
内部函数与变量的种类一起使用。
INT()
内部函数的定义是 (16.9.100(5)):
Result Value.
Case (i): If A is of type integer, INT (A) = A.
...
其中 A
是参数。
所以它只是说值被复制了。如果该值不合适,那你就不走运了。 Fortran 标准没有定义会发生什么,因为(正如@steve 所指出的):
F2018 16.9.1(2)
A program shall not invoke an intrinsic procedure under circumstances
where a value to be assigned to a subroutine argument or returned as a
function result is not representable by objects of the specified type
and type parameters.
这使您的程序不符合规范。在 C 中,他们会说行为是未定义的(不仅仅是实现定义的)。
如果启用 -Wconversion
并在没有显式 int()
内在的情况下进行赋值,您将收到可能值更改的警告。确实,在a = b
你可以看到这样的变化。
如果启用 -fsanitization=undefined
并执行相同的操作,则可能会出现运行时错误。我现在重现不了,但我以前确实打过这样的东西。
触发检查必须是真正的运行时:
use iso_fortran_env
integer(int32) :: b
read *,b
b = 2*b
print *, b
end
> gfortran conversion2.f90 -fsanitize=signed-integer-overflow
> ./a.out
2000000000
conversion2.f90:4: runtime error: signed integer overflow: 2000000000 * 2 cannot be represented in type 'integer(kind=4)'
-294967296
考虑以下代码片段:
integer(int8) :: a
integer(int32) :: b
integer(int64) :: c
a = - huge(a) - 1
b = - huge(b) - 1
c = - huge(c) - 1
print *, a, b, c
a = int(b, kind=int8)
c = int(b, kind=int64)
print *, a, b, c
在我的系统上它给出了以下输出:
-128 -2147483648 -9223372036854775808
0 -2147483648 -2147483648
这表明不同种类整数之间的转换发生如下:
- 扩大整数转换[更少的字节到更多的字节]是通过符号扩展完成的。
- 缩小整数转换[更多字节到更少字节]是通过简单地去掉高阶位来完成的。
这类似于Java的整数转换规则。
行为是否定义为标准 Fortran?有什么方法可以覆盖规则 1 并简单地获得正常的加宽 [比如 Java 的 Integer.toUnsignedLong()]?
编译器信息:
GNU Fortran (Rev6, Built by MSYS2 project) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
在F2018的10.2.1.3(8)你会发现内在赋值右边表达式的值是按照一个table转换的。当分配给整数的变量时,INT()
内部函数与变量的种类一起使用。
INT()
内部函数的定义是 (16.9.100(5)):
Result Value.
Case (i): If A is of type integer, INT (A) = A.
...
其中 A
是参数。
所以它只是说值被复制了。如果该值不合适,那你就不走运了。 Fortran 标准没有定义会发生什么,因为(正如@steve 所指出的):
F2018 16.9.1(2)
A program shall not invoke an intrinsic procedure under circumstances where a value to be assigned to a subroutine argument or returned as a function result is not representable by objects of the specified type and type parameters.
这使您的程序不符合规范。在 C 中,他们会说行为是未定义的(不仅仅是实现定义的)。
如果启用 -Wconversion
并在没有显式 int()
内在的情况下进行赋值,您将收到可能值更改的警告。确实,在a = b
你可以看到这样的变化。
如果启用 -fsanitization=undefined
并执行相同的操作,则可能会出现运行时错误。我现在重现不了,但我以前确实打过这样的东西。
触发检查必须是真正的运行时:
use iso_fortran_env
integer(int32) :: b
read *,b
b = 2*b
print *, b
end
> gfortran conversion2.f90 -fsanitize=signed-integer-overflow
> ./a.out
2000000000
conversion2.f90:4: runtime error: signed integer overflow: 2000000000 * 2 cannot be represented in type 'integer(kind=4)'
-294967296