字符串连接在 Fortran 中不起作用
String concatenation not working in Fortran
我有一个连接字符串以创建文件名的子例程,这样我就可以跟踪解决方案在非线性迭代中的变化。但是它似乎不起作用。我以前使用过这个代码片段没有任何问题所以我想知道这是否依赖于某些编译器标志?字符串连接部分在底部,我return如下:
output_name:PLT/Res
文件名1:
PLT/Res
文件名2:
PLT/Res
写入文件... 0
这清楚地表明我的字符串没有串联。
我调用子例程:
IF (MOD(counter, plot_freq) == 0) call plotSolution(2, counter, 'PLT/Solution', Mesh, W)
例程如下。
subroutine plot_nodal_field(opt, iter, output_file, Mesh, Q)
use Globals_module, only : c_in
use inputs_module, only : p_in, gamma, rho_in, M_inf
!--------------------------------------------end of use--------------------------------------------!
integer(i4), intent(in) :: iter, opt
type(Mesh_Type), intent(in) :: Mesh
character(*), intent(in) :: output_file
real(dp), intent(in) :: Q(Mesh%numFields, Mesh%numNodes)
!------------------------------------------end of intents------------------------------------------!
integer(i4) :: elem_id,n1,n2,n3
character(80) :: filename, file_num
integer(i4) :: iunit
integer(i4) :: n,io, i
real(dp) :: x, y, rho, rhoU, rhoV, rhoE, u, v, P, CP, c, MachNum, s
!------------------------------------------end of declare------------------------------------------!
iunit = 2
write(file_num,'(I6.6)') iter
write(*,*) 'output_name:', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,'(A)') 'filename1:', filename
filename = adjustl(trim(filename))
write(*,'(A)') 'filename2:', filename
print*,'# Writing to File...', iter
open(unit = iunit, file = filename, status = 'replace', iostat = io)
if( io /= 0) then
print*,'ERROR: Opening 2nd order plt file'
else
if (opt == 1) then
write(iunit,'(A)') 'VARIABLES = "x","y","rho","U","V","P","MachNum","entropy"'
elseif(opt == 2) then
write(iunit,'(A)') 'VARIABLES = "x","y","rho","U","V","P"'
end if
write(iunit,'(A7, I, A3, I, A41)') 'ZONE N=', Mesh%numNodes, ' E=', Mesh%numTri, ' DATAPACKING=POINT ZONETYPE=FETRIANGLE'
do i = 1, Mesh%numNodes
x = Mesh%nodeCoords(1, i)
y = Mesh%nodeCoords(2, i)
if (opt == 1) then
rho = Q(1, i)
U = Q(2, i)
V = Q(3, i)
P = Q(4, i)
c = sqrt(gamma*P/Q(1,i))
MachNum = sqrt(Q(2,i)**2 + Q(3,i)**2)/c
s = P/Q(1,i)**gamma - P_in/rho_in**gamma
write(iunit,'(8ES)') Real(x), Real(y), Real(Q(1,i)), Real(Q(2,i)), Real(Q(3,i)), Real(Q(4,i)), &
& Real(MachNum), Real(s)
elseif (opt == 2) then
write(iunit,'(6ES)') Real(x), Real(y), Real(Q(1,i)), Real(Q(2,i)), Real(Q(3,i)), Real(Q(4,i))
end if
end do
do i = 1, Mesh%numTri
write(iunit,'(3I)') Mesh%trilist(1,i), Mesh%trilist(2,i), Mesh%trilist(3,i)
end do
end if
close(iunit)
end subroutine
编辑:
我试着做了一个最小可验证的例子:
program plotSolution
!--------------------------------------------end of use--------------------------------------------!
integer :: iter
character(80) :: filename
!------------------------------------------end of intents------------------------------------------!
filename = 'PLT/Solution'
iter = 1
call plot_nodal_field(iter, filename)
contains
subroutine plot_nodal_field(iter, output_file)
!--------------------------------------------end of use--------------------------------------------!
integer, intent(in) :: iter
character(*), intent(in) :: output_file
!------------------------------------------end of intents------------------------------------------!
character(80) :: filename, file_num
integer :: iunit
!------------------------------------------end of declare------------------------------------------!
iunit = 2
write(file_num,'(I6.6)') iter
write(*,*) 'output_name:', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,'(A)') 'filename1:', filename
filename = adjustl(trim(filename))
write(*,'(A)') 'filename2:', filename
print*,'# Writing to File...', iter
open(unit = iunit, file = filename, status = 'replace', iostat = io)
if( io /= 0) then
print*,'ERROR: Opening 2nd order plt file'
else
end if
close(iunit)
end subroutine
end program
但这行得通:
和 returns:
output_name:
PLT/Solution
文件名1:
PLT/Solution_000001.plt
文件名2:
PLT/Solution_000001.plt
写入文件... 1
错误:打开二阶 plt 文件
这表明我在主代码中可能有一些奇怪的内存错误。我不确定。感谢所有的建议和帮助!
我使用这个测试程序尝试了发布的例程:
- 我找不到 gfortran>=5.3.0 的问题,但根据我的经验,gfortran 的字符串处理在过去的版本中一直存在很多问题;
- 每当我有 variable-size 个字符串时,我的编码习惯是有一个 fixed-length 字符串缓冲区(比如
character(len=BUFFER_SIZE) :: buffer
),以进行所有临时剪切和粘贴,然后分配函数末尾 variable-length 变量的相关部分(选择最大长度的盐粒!)
- 在附加示例中,我发布了示例路径创建函数。它可以被概括为更灵活的使用(文件夹名称的选择等);
program test_string
implicit none
integer :: counter
character(len=:), allocatable :: fileName
counter = 2
! Original routine
call create_string_orig(counter,'PLT/Solution')
! With path function
fileName = output_fileName('PLT',counter)
write(*,*) 'filename with function: ', fileName
contains
function output_fileName(folder,iter) result(fileName)
character(*), intent(in) :: folder
integer, intent(in) :: iter
character(len=:), allocatable :: fileName
! Local variables
character(*), parameter :: prefix = 'Solution'
character(*), parameter :: ext = '.plt'
character(len=1024) :: buffer
character(len=6) :: fileID
integer :: fullLen
write(fileID,'(I6.6)') iter
buffer = trim(adjustl(folder)) // filesep() // prefix // '_' // fileID // ext
fullLen = len_trim(buffer)
allocate(character(len=fullLen) :: fileName)
fileName(1:fullLen) = buffer(1:fullLen)
end function output_fileName
! Get current system's folder separator
character function filesep()
character(len=9999) :: system_path
integer :: i
system_path = repeat(' ',len(system_path))
call get_environment_variable('PATH',system_path)
do i = 1, len(system_path)
if (system_path(i:i) == '/') then
filesep = '/'
return
elseif (system_path(i:i) == '\') then
filesep = '\'
return
endif
end do
! Use default if unable to find a separator
filesep = '/'
return
end function filesep
subroutine create_string_orig(iter,output_file)
integer, intent(in) :: iter
character(*), intent(in) :: output_file
character(80) :: filename,file_num
write(file_num,'(I6.6)') iter
write(*,*) 'output_name: ', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,*) 'filename1: ', filename
filename = adjustl(trim(filename))
write(*,*) 'filename2: ', filename
print*,'# Writing to File...', iter
end subroutine create_string_orig
end program
产生以下输出(在 Windows 上工作):
$ a.exe
output_name: PLT/Solution
filename1: PLT/Solution_000002.plt
filename2: PLT/Solution_000002.plt
# Writing to File... 2
filename with function: PLT\Solution_000002.plt
非常感谢你们提供的所有帮助,并决定今天 return 解决此问题并找到问题所在。据我所知,这是一个编译器标志问题,其中 compiler/preprocessor 将连接运算符 (//) 作为 C++ 注释,预处理器在连接后注释掉所有内容。我不得不使用延续符号拼凑出一个修复程序,但它现在有效,然后我可以下次查看这些标志。如果有人有任何见解,我将不胜感激。
我有一个连接字符串以创建文件名的子例程,这样我就可以跟踪解决方案在非线性迭代中的变化。但是它似乎不起作用。我以前使用过这个代码片段没有任何问题所以我想知道这是否依赖于某些编译器标志?字符串连接部分在底部,我return如下:
output_name:PLT/Res
文件名1:
PLT/Res
文件名2:
PLT/Res
写入文件... 0
这清楚地表明我的字符串没有串联。 我调用子例程:
IF (MOD(counter, plot_freq) == 0) call plotSolution(2, counter, 'PLT/Solution', Mesh, W)
例程如下。
subroutine plot_nodal_field(opt, iter, output_file, Mesh, Q)
use Globals_module, only : c_in
use inputs_module, only : p_in, gamma, rho_in, M_inf
!--------------------------------------------end of use--------------------------------------------!
integer(i4), intent(in) :: iter, opt
type(Mesh_Type), intent(in) :: Mesh
character(*), intent(in) :: output_file
real(dp), intent(in) :: Q(Mesh%numFields, Mesh%numNodes)
!------------------------------------------end of intents------------------------------------------!
integer(i4) :: elem_id,n1,n2,n3
character(80) :: filename, file_num
integer(i4) :: iunit
integer(i4) :: n,io, i
real(dp) :: x, y, rho, rhoU, rhoV, rhoE, u, v, P, CP, c, MachNum, s
!------------------------------------------end of declare------------------------------------------!
iunit = 2
write(file_num,'(I6.6)') iter
write(*,*) 'output_name:', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,'(A)') 'filename1:', filename
filename = adjustl(trim(filename))
write(*,'(A)') 'filename2:', filename
print*,'# Writing to File...', iter
open(unit = iunit, file = filename, status = 'replace', iostat = io)
if( io /= 0) then
print*,'ERROR: Opening 2nd order plt file'
else
if (opt == 1) then
write(iunit,'(A)') 'VARIABLES = "x","y","rho","U","V","P","MachNum","entropy"'
elseif(opt == 2) then
write(iunit,'(A)') 'VARIABLES = "x","y","rho","U","V","P"'
end if
write(iunit,'(A7, I, A3, I, A41)') 'ZONE N=', Mesh%numNodes, ' E=', Mesh%numTri, ' DATAPACKING=POINT ZONETYPE=FETRIANGLE'
do i = 1, Mesh%numNodes
x = Mesh%nodeCoords(1, i)
y = Mesh%nodeCoords(2, i)
if (opt == 1) then
rho = Q(1, i)
U = Q(2, i)
V = Q(3, i)
P = Q(4, i)
c = sqrt(gamma*P/Q(1,i))
MachNum = sqrt(Q(2,i)**2 + Q(3,i)**2)/c
s = P/Q(1,i)**gamma - P_in/rho_in**gamma
write(iunit,'(8ES)') Real(x), Real(y), Real(Q(1,i)), Real(Q(2,i)), Real(Q(3,i)), Real(Q(4,i)), &
& Real(MachNum), Real(s)
elseif (opt == 2) then
write(iunit,'(6ES)') Real(x), Real(y), Real(Q(1,i)), Real(Q(2,i)), Real(Q(3,i)), Real(Q(4,i))
end if
end do
do i = 1, Mesh%numTri
write(iunit,'(3I)') Mesh%trilist(1,i), Mesh%trilist(2,i), Mesh%trilist(3,i)
end do
end if
close(iunit)
end subroutine
编辑:
我试着做了一个最小可验证的例子:
program plotSolution
!--------------------------------------------end of use--------------------------------------------!
integer :: iter
character(80) :: filename
!------------------------------------------end of intents------------------------------------------!
filename = 'PLT/Solution'
iter = 1
call plot_nodal_field(iter, filename)
contains
subroutine plot_nodal_field(iter, output_file)
!--------------------------------------------end of use--------------------------------------------!
integer, intent(in) :: iter
character(*), intent(in) :: output_file
!------------------------------------------end of intents------------------------------------------!
character(80) :: filename, file_num
integer :: iunit
!------------------------------------------end of declare------------------------------------------!
iunit = 2
write(file_num,'(I6.6)') iter
write(*,*) 'output_name:', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,'(A)') 'filename1:', filename
filename = adjustl(trim(filename))
write(*,'(A)') 'filename2:', filename
print*,'# Writing to File...', iter
open(unit = iunit, file = filename, status = 'replace', iostat = io)
if( io /= 0) then
print*,'ERROR: Opening 2nd order plt file'
else
end if
close(iunit)
end subroutine
end program
但这行得通: 和 returns:
output_name: PLT/Solution
文件名1:
PLT/Solution_000001.plt
文件名2:
PLT/Solution_000001.plt
写入文件... 1
错误:打开二阶 plt 文件
这表明我在主代码中可能有一些奇怪的内存错误。我不确定。感谢所有的建议和帮助!
我使用这个测试程序尝试了发布的例程:
- 我找不到 gfortran>=5.3.0 的问题,但根据我的经验,gfortran 的字符串处理在过去的版本中一直存在很多问题;
- 每当我有 variable-size 个字符串时,我的编码习惯是有一个 fixed-length 字符串缓冲区(比如
character(len=BUFFER_SIZE) :: buffer
),以进行所有临时剪切和粘贴,然后分配函数末尾 variable-length 变量的相关部分(选择最大长度的盐粒!) - 在附加示例中,我发布了示例路径创建函数。它可以被概括为更灵活的使用(文件夹名称的选择等);
program test_string
implicit none
integer :: counter
character(len=:), allocatable :: fileName
counter = 2
! Original routine
call create_string_orig(counter,'PLT/Solution')
! With path function
fileName = output_fileName('PLT',counter)
write(*,*) 'filename with function: ', fileName
contains
function output_fileName(folder,iter) result(fileName)
character(*), intent(in) :: folder
integer, intent(in) :: iter
character(len=:), allocatable :: fileName
! Local variables
character(*), parameter :: prefix = 'Solution'
character(*), parameter :: ext = '.plt'
character(len=1024) :: buffer
character(len=6) :: fileID
integer :: fullLen
write(fileID,'(I6.6)') iter
buffer = trim(adjustl(folder)) // filesep() // prefix // '_' // fileID // ext
fullLen = len_trim(buffer)
allocate(character(len=fullLen) :: fileName)
fileName(1:fullLen) = buffer(1:fullLen)
end function output_fileName
! Get current system's folder separator
character function filesep()
character(len=9999) :: system_path
integer :: i
system_path = repeat(' ',len(system_path))
call get_environment_variable('PATH',system_path)
do i = 1, len(system_path)
if (system_path(i:i) == '/') then
filesep = '/'
return
elseif (system_path(i:i) == '\') then
filesep = '\'
return
endif
end do
! Use default if unable to find a separator
filesep = '/'
return
end function filesep
subroutine create_string_orig(iter,output_file)
integer, intent(in) :: iter
character(*), intent(in) :: output_file
character(80) :: filename,file_num
write(file_num,'(I6.6)') iter
write(*,*) 'output_name: ', output_file
filename = adjustl(trim(output_file)) // '_' // adjustl(trim(file_num)) // '.plt'
write(*,*) 'filename1: ', filename
filename = adjustl(trim(filename))
write(*,*) 'filename2: ', filename
print*,'# Writing to File...', iter
end subroutine create_string_orig
end program
产生以下输出(在 Windows 上工作):
$ a.exe
output_name: PLT/Solution
filename1: PLT/Solution_000002.plt
filename2: PLT/Solution_000002.plt
# Writing to File... 2
filename with function: PLT\Solution_000002.plt
非常感谢你们提供的所有帮助,并决定今天 return 解决此问题并找到问题所在。据我所知,这是一个编译器标志问题,其中 compiler/preprocessor 将连接运算符 (//) 作为 C++ 注释,预处理器在连接后注释掉所有内容。我不得不使用延续符号拼凑出一个修复程序,但它现在有效,然后我可以下次查看这些标志。如果有人有任何见解,我将不胜感激。