GNU Fortran 编译器的 GNU 扩展提供了GETCWD()
很好的子例程,可以获取当前工作目录。但是,我的代码必须可移植到ifort
andnagfor
器,并且我使用 F2003 功能。
那么,是否有替代方案GETCWD()
那么,对于 F2003 及更高版本
我这里有标准,但它相当大,我已经经历了一段时间,没有发现任何有用的东西......
GNU Fortran 编译器的 GNU 扩展提供了GETCWD()
很好的子例程,可以获取当前工作目录。但是,我的代码必须可移植到ifort
andnagfor
器,并且我使用 F2003 功能。
那么,是否有替代方案GETCWD()
那么,对于 F2003 及更高版本
我这里有标准,但它相当大,我已经经历了一段时间,没有发现任何有用的东西......
如评论中所述,您可以使用get_environment_variable
标准 Fortran(例如 F2008 13.7.67)。此示例程序查询 的值$PWD
,该值应包含您调用可执行文件时 shell 所在的目录。
program test
implicit none
character(len=128) :: pwd
call get_environment_variable('PWD',pwd)
print *, "The current working directory is: ",trim(pwd)
end program
及其输出:
casey@convect code % pwd
/home/casey/code
casey@convect code % so/getpwd
The current working directory is: /home/casey/code
这是标准的 Fortran,但它的可移植性仅限于设置此变量的 Unix 和类 Unix shell。
另一个标准但丑陋的选择(在我看来)是使用execute_command_line
运行一个可以将工作目录输出到临时文件(例如pwd > /tmp/mypwd
)的命令,然后读取该文件。
也可以使用ISO_C_Binding
and 调用相应的C
函数:
cwd.c:
#ifdef _WIN32
/* Windows */
#include <direct.h>
#define GETCWD _getcwd
#else
/* Unix */
#include <unistd.h>
#define GETCWD getcwd
#endif
void getCurrentWorkDir( char *str, int *stat )
{
if ( GETCWD(str, sizeof(str)) == str ) {
*stat = 0;
} else {
*stat = 1;
}
}
测试.F90:
program test
use ISO_C_Binding, only: C_CHAR, C_INT
interface
subroutine getCurrentWorkDir(str, stat) bind(C, name="getCurrentWorkDir")
use ISO_C_Binding, only: C_CHAR, C_INT
character(kind=C_CHAR),intent(out) :: str(*)
integer(C_INT),intent(out) :: stat
end subroutine
end interface
character(len=30) :: str
integer(C_INT) :: stat
str=''
call getCurrentWorkDir(str, stat)
print *, stat, trim(str)
end program
此代码适用于 Windows 和 Unix 衍生版本(Linux、OSX、BSD 等)
接受的答案包含两个错误(它将错误的值作为字符串的长度传递给GETCWD
,并留在 中C_NULL_CHAR
)。这个答案纠正了这些错误,并使界面在 Fortran 中更有用。
基本思想是相同的:调用getcwd
或_getcwd
使用 C,并使用 Fortran 的 C 互操作性特性调用 C 包装器。在 Fortran 方面,包装子例程用于处理字符串长度,因此不必显式传递。
此外,C_INT
并且C_CHAR
不需要与 Fortran 端需要的默认整数和默认字符相同(尽管实际上我不知道任何系统在哪里C_CHAR
和默认字符不同)。包装器也会转换那些。此外,从 C 返回的字符串包含终止符C_NULL_CHAR
,必须删除它才能使字符串在 Fortran 端可用。
C代码:
#ifdef _WIN32
#include <direct.h>
#define GETCWD _getcwd
#else
#include <unistd.h>
#define GETCWD getcwd
#endif
/* Return 0 on success, 1 on error. */
int getCWDHelper(char *str, int len)
{
return GETCWD(str, len) != str;
}
Fortran 代码:
module cwd
use iso_c_binding, only: C_INT, C_CHAR, C_NULL_CHAR
implicit none
private
public :: getCWD
interface
function getCWDHelper(str, len) bind(C, name="getCWDHelper")
use iso_c_binding, only: C_INT, C_CHAR
integer(kind=C_INT) :: getCWDHelper
character(kind=C_CHAR), intent(out) :: str(*)
integer(kind=C_INT), value :: len
end function getCWDHelper
end interface
contains
! Writes the current working directory path into str.
! Returns 0 on success, or 1 on error.
function getCWD(str)
integer :: getCWD
character(*), intent(out) :: str
integer :: i, length
character(len=len(str), kind=C_CHAR) :: str_copy
! Call the C helper, passing the length as the correct int kind
getCWD = getCWDHelper(str_copy, len(str_copy, kind=C_INT))
if (getCWD /= 0) then
str = '' ! Error, clear the string
return
end if
! Copy the C_CHAR string to the output string,
! removing the C_NULL_CHAR and clearing the rest.
length = index(str_copy, C_NULL_CHAR) - 1
do i = 1, length
str(i:i) = char(ichar(str_copy(i:i)))
end do
str(length+1:) = ''
end function getCWD
end module
测试代码:
program test
use cwd, only: getCWD
implicit none
character(len=255) :: path
integer :: error
error = getCWD(path)
print *, error
if (error == 0) print *, path
end program
使返回值可分配并循环以获得足够的大小作为练习留给读者。