【问题标题】:What happens when calling external an Fortran function with the wrong type of arguments?使用错误类型的参数调用外部 Fortran 函数时会发生什么?
【发布时间】:2018-07-09 18:59:26
【问题描述】:

如果您在文件(而不是模块)中有一个独立的函数,并且您使用单精度调用它,而它需要一个双精度数:

main.f90:

program main

  call test(1.0)
end program main

test.f90:

subroutine test(a)
    double precision :: a
    print *, "a", a
end subroutine

在这种情况下,编译器如何将单精度“转换”为双精度? 使用浮点格式,我希望这些位在强制转换期间保持不变,但要附加额外的零。那就是:

1 = 0 01111111 00000000000000000000000 in single-precision

我希望最终值为 2^(-7):

0 01111111000 0000000000000000000000000000000000000000000000000000 in double precision

令人惊讶的是,使用 gfortran 6.4.0,最终值为 5.2635442471208903E-315。

【问题讨论】:

    标签: floating-point fortran gfortran


    【解决方案1】:

    编译器不进行强制转换。你写的不是 Fortran。

    在主程序中,子程序test 有一个隐式接口。本质上,编译器对此一无所知,只是它是一个子例程。您还告诉它它有一个(默认)实参数。

    在引用子例程时提供正确类型和种类的参数是您的责任,而不是编译器的责任。你在那里失败了,所以你没有一个兼容的 Fortran 程序。 Fortran 编译器不欠你任何东西。

    您将观察到的内容取决于 Fortran 处理器的实现细节。该子例程需要一个双精度参数,并且没有理由相信它还有其他任何东西。无论是copy-in/copy-out还是某个地址传递1,内存的解释都会不匹配。在 dummy 参数中,除了实际参数的默认实数对应的字节外,所有字节都是“垃圾”。

    如果您在主程序中为子例程提供显式接口,仍然不会进行强制转换,但编译器会注意到不匹配。同样,即使存在隐式接口,某些编译器(可能带有某些编译标志)也会进行一些检查。


    1有关可能的传递引用的详细信息,请参阅 user5713492 的评论。

    【讨论】:

    • 很高兴您将这些详细信息添加到我的答案中。我也可以这样做,但是如果您复制出处,则更清楚。无论哪种方式:感谢您的更正。
    【解决方案2】:

    我猜编译器会根据字节序“强制转换”。如果你在左边加零,你会得到:

    0 00000000000 0000000000000000000000111111100000000000000000000000
    

    这是 5.2635442471208903E-315。您可以通过在编译时强制字节顺序进行检查。

    【讨论】:

    • 不保证将读取的额外字节全为零;它应该是来自随机内存位置的“垃圾”数据
    • 即使读取了垃圾数据也无法保证。这是错误的。任何事情都有可能发生,包括鼻部守护进程。
    猜你喜欢
    • 2016-08-18
    • 2014-11-11
    • 2013-09-17
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-07-12
    相关资源
    最近更新 更多