Fortran 2003-2008 中是否有 GETCWD() 的替代方法
Is there an alternative to GETCWD() in Fortran 2003-2008
GNU Fortran 编译器的 GNU 扩展提供了子程序 GETCWD()
,它可以获取当前工作目录。但是,我的代码也必须可移植到 ifort
和 nagfor
编译器,并且我使用 F2003 功能。
那么,对于 F2003 及更高版本,是否有 GETCWD()
的替代方案?
我这里有标准,但它相当大,我已经研究了一段时间,但没有发现任何有用的东西...
如评论中所述,您可以使用标准 Fortran(例如 F2008 13.7.67)的 get_environment_variable
。此示例程序查询 $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
并调用相应的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 中更可用。
基本思路相同:使用 C 调用 getcwd
或 _getcwd
,并使用 Fortran 的 C 互操作性功能调用 C 包装器。在 Fortran 方面,包装器子例程用于处理字符串长度,因此不必显式传递。
此外,C_INT
和 C_CHAR
不需要与默认整数和默认字符相同,它们在 Fortran 方面是需要的(尽管实际上我不知道任何系统 C_CHAR
和默认字符不同)。包装器也会转换那些。此外,来自 C 的字符串 returned 包含终止符 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
使 return 值可分配并循环以获得足够的大小作为 reader.
的练习。
GNU Fortran 编译器的 GNU 扩展提供了子程序 GETCWD()
,它可以获取当前工作目录。但是,我的代码也必须可移植到 ifort
和 nagfor
编译器,并且我使用 F2003 功能。
那么,对于 F2003 及更高版本,是否有 GETCWD()
的替代方案?
我这里有标准,但它相当大,我已经研究了一段时间,但没有发现任何有用的东西...
如评论中所述,您可以使用标准 Fortran(例如 F2008 13.7.67)的 get_environment_variable
。此示例程序查询 $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
并调用相应的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 中更可用。
基本思路相同:使用 C 调用 getcwd
或 _getcwd
,并使用 Fortran 的 C 互操作性功能调用 C 包装器。在 Fortran 方面,包装器子例程用于处理字符串长度,因此不必显式传递。
此外,C_INT
和 C_CHAR
不需要与默认整数和默认字符相同,它们在 Fortran 方面是需要的(尽管实际上我不知道任何系统 C_CHAR
和默认字符不同)。包装器也会转换那些。此外,来自 C 的字符串 returned 包含终止符 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
使 return 值可分配并循环以获得足够的大小作为 reader.
的练习。