【问题标题】:String array being nullified when passing传递时字符串数组被无效
【发布时间】:2018-07-26 03:48:31
【问题描述】:

我在传递字符串数组时遇到问题。考虑以下示例代码:

! -- Module to declare variable
module my_data
   implicit none

   ! -- Declare as deferred-length allocatable array
   character(len=:), dimension(:), allocatable :: str_array
end module my_data

! -- Module to call subroutine
module my_subs
   implicit none

contains
subroutine a(str_array)
   character(len=*), dimension(:), intent(IN) :: str_array
   integer :: i, j
   character :: c

   do i=1,size(str_array)
      do j=1,len_trim(str_array(i))
         c = str_array(i)(j:j)

         ! -- Write i, j, character, and int representation
         write(*,*) 'In call: ', i, j, ' "'//c//'", ichar = ', ichar(c)
      enddo
   enddo
end subroutine a
end module my_subs

! -- Main program
program main
   use my_data, only : str_array
   use my_subs, only : a
   implicit none
   integer, parameter :: strlen = 200
   integer :: N, i, j
   character :: c

   ! -- Size of str array
   N = 2

   ! -- Allocate str_array, syntax from https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/287349
   allocate(character(strlen) :: str_array(N))

   ! -- Set both to the same string
   str_array = 'abc'

   do i=1,size(str_array)
      do j=1,len_trim(str_array(i))
         c = str_array(i)(j:j)

         ! -- Write i, j, character, and int representation
         write(*,*) 'In main: ', i, j, ' "'//c//'", ichar = ', ichar(c)
      enddo
   enddo

   call a(str_array)
end program main

字符串数组被声明为假定长度元素的数组(来自the wiki)。我分配和设置字符串的值(两个元素,在这个例子中都是abc)。主程序输出有关字符串的完整详细信息,然后调用一个子程序,该子程序也输出(希望是相同的)完整详细信息。

使用 PGI、GCC 或 Intel 15.0,我得到了我期望的结果:

chaud106@ln0005 [~/Testing] % ifort --version && ifort -check all -warn all main.f90 && ./a.out
ifort (IFORT) 15.0.3 20150407
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

 In main:            1           1  "a", ichar =           97
 In main:            1           2  "b", ichar =           98
 In main:            1           3  "c", ichar =           99
 In main:            2           1  "a", ichar =           97
 In main:            2           2  "b", ichar =           98
 In main:            2           3  "c", ichar =           99
 In call:            1           1  "a", ichar =           97
 In call:            1           2  "b", ichar =           98
 In call:            1           3  "c", ichar =           99
 In call:            2           1  "a", ichar =           97
 In call:            2           2  "b", ichar =           98
 In call:            2           3  "c", ichar =           99

但是,Intel 18.0 将字符数组的第二个元素(所有 3 个字符)设置为空字符:

chaud106@ln0005 [~/Testing] % ifort --version && ifort -check all -warn all main.f90 && ./a.out
ifort (IFORT) 18.0.0 20170811
Copyright (C) 1985-2017 Intel Corporation.  All rights reserved.

 In main:            1           1  "a", ichar =           97
 In main:            1           2  "b", ichar =           98
 In main:            1           3  "c", ichar =           99
 In main:            2           1  "a", ichar =           97
 In main:            2           2  "b", ichar =           98
 In main:            2           3  "c", ichar =           99
 In call:            1           1  "a", ichar =           97
 In call:            1           2  "b", ichar =           98
 In call:            1           3  "c", ichar =           99
 In call:            2           1  "", ichar =            0
 In call:            2           2  "", ichar =            0
 In call:            2           3  "", ichar =            0

我有几个与此行为相关的问题:

  1. 为什么会发生这种情况?我在想这可能与英特尔强制执行 lhs-relocation 有关,但我不确定。添加-assume norealloc_lhs 并没有改变任何东西。

  2. 传递这样的字符串数组的正确语法是什么?我可以用不同的方式声明它并避免这个问题吗?

我在这台机器上可以访问的 Intel 版本具有以下行为:

  • ifort (IFORT) 15.0.2 20150121 - 不作废
  • ifort (IFORT) 15.0.3 20150407 - 不作废
  • ifort (IFORT) 16.0.3 20160415 - 不作废
  • ifort (IFORT) 17.0.4 20170411 - 无效
  • ifort (IFORT) 18.0.0 20170811 - 无效

在另一台机器上,我没有任何最新的英特尔:

  • ifort (IFORT) 14.0.2 20140120 - 不作废
  • ifort (IFORT) 16.0.0 20150815 - 不作废

【问题讨论】:

  • 你能用 18.0.3 试试吗?
  • @francescalus 不容易,不。我将编辑问题以包含有关我在这台机器上可以访问的英特尔版本的更多细节。
  • @francescalus 根据我可以访问的版本,该行为发生在版本 16.0.3 和 17.0.4 之间 - 差不多一年。如果在此期间有人可以访问版本,那么进行测试可能会很好。
  • 我也在英特尔论坛上发布了这个,因为它似乎是针对他们的编译器的:software.intel.com/en-us/forums/…
  • 我回答了这个问题,尽管在当前版本中已修复,部分原因是(没有剧透!)还有其他编译器受到影响。我不会回复英特尔论坛主题,但请注意,需要在问题代码的分配中重新分配str_array

标签: fortran intel-fortran


【解决方案1】:

您的程序在 ifort 18.0.3 上按预期运行。

我没有尝试过很多以前的版本,但我注意到 17.0.1 是 Fortran 2003 对内在赋值的自动分配成为该编译器的默认设置的点。

有问题的行似乎是

str_array = 'abc'

这里,str_array 应该首先被释放,因为右边是一个与左边不同长度参数的表达式。然后它将被分配为长度为 3 的字符(右手边的长度)和形状 [2] 和以前一样(右手边是标量)。这确实发生了,正如SIZE(str_array)LEN(str_array) 所见。不过,稍后将其用作实际参数时会出现一些问题。

有一些方法可以解决 18.0.1 的这个问题:

  • 为虚拟参数赋予value 属性;
  • str_array = ['abc','abc'](不需要之前的分配);
  • str_array(:) = 'abc'(如果您不想重新分配)。

可能还有许多其他可用,具体取决于您的需要。不过,如果可以,请将您的编译器升级到最新版本。

【讨论】:

  • 你说得对,使用str_array(:) = 'abc' 的分配是正确的,所以我现在可能会使用它。我如何知道哪些分配方法会导致(重新)分配?
  • 另外,我很奇怪在编译时包含 assume -norealloc_lhs 并没有帮助 Intel 18.0 的行为。也许我会在英特尔特定的论坛上发帖,并尝试更多地了解“稍后会出现一些问题”的部分。
  • -假设 [no]realloc_lhs 从未影响可分配的延迟长度字符分配。这仅适用于在 Fortran 90 中有效的数组分配。
  • @francescalus ,F90 中不存在延迟长度字符分配。 ifort realloc_lhs 选项仅适用于重新分配具有不同形状的数组。无论如何,新语法都会对不同长度的字符进行重新分配。 (引入了对字符(:) 的支持的初始测试版确实将它与 realloc_lhs 联系在一起,但在发布版本之前已修复。)但如果你有,'abc' 是一个标量,因此它扩展为相同的形状作为 str_array 并且没有重新分配但是如果形状不同,它会重新分配而不管选项。
  • 我的意思是,对于延迟长度的字符可分配对象,ifort 应用当前的标准语义并执行重新分配(如果需要),无论您对 -assume realloc_lhs 说什么。
猜你喜欢
  • 2018-03-01
  • 1970-01-01
  • 2014-09-06
  • 1970-01-01
  • 1970-01-01
  • 2016-11-16
  • 2010-12-15
  • 2017-04-21
  • 2018-11-23
相关资源
最近更新 更多