从 gdb 调用派生类型的 fortran 子例程
Calling fortran subroutines of derived types from gdb
我想调用一个函数,该函数将 Gnu 调试器 (gdb) 中的派生类型作为参数。我最终遇到了段错误。这是一个“最小”工作示例:
module modSimpleClass
type Person
character(len=20) :: Name
contains
procedure PrintName
end type
contains
subroutine PrintName(a)
class(Person) :: a
print *, a%Name
end subroutine
subroutine Print42()
print *, "42"
end subroutine
subroutine PrintNameFromOutside(a)
class(Person) :: a
print *, a%Name
end subroutine
end module
program testgdb
use modSimpleClass
implicit none
type(Person) :: JoeJohnson
JoeJohnson%Name = "Joe Johnson"
call JoeJohnson%PrintName
end program testgdb
我用 gfortran 版本 9.3.0 编译它,运行 从 gdb 编译它并在结束前停止它。
以下内容有效:
call Print42()
print JoeJohnson%Name
以下内容不起作用:
call JoeJohnson%PrintName()!There is no member named PrintName.
call PrintName(JoeJohnson)!Error then segfault
call PrintNameFromOutside(JoeJohnson)!Error then segfault
错误如下:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(modsimpleclass::printname) will be abandoned.
When the function is done executing, GDB will silently stop.
如何从gdb正确调用fortran子程序?
感谢@Flusslauf 的回复。我将尝试重新表述您所说的话:
从 gfortran 的角度来看,如果我们在模块 modsimpleclass
中定义派生类型 Person
,
- 只有初始化变量的作用域才能看到原始类型。
- 任何以参数为参数的函数或子程序
该派生类型的对象看到类型
__class_modsimpleclass_Person_t
具有属性:
_data
: 指向对象的指针。
_vptr
:指向包含对象信息的指针。
所以函数实际上为派生类型的每个对象使用两个指针:一个指向对象
另一个指向有关对象的信息。
在 gdb 中,将指向对象的指针传递给函数,
但是传递给它的对象本身不起作用。
@Flusslauf 成立
call PrintName( &JoeJohnson )!works because it is equivalent to
call PrintName( a%_data )!this, which works too
call PrintName( a )!this works and it makes sense
call PrintName( a%_data, a%_vptr )!this also works
call PrintName( a%_vptr)!this outputs something strange
call PrintName( *(a%_data) )!causes segfault since equivalent to
call PrintName( JoeJohnson )!Error then segfault
,其中每条指令都在变量的正确范围内执行。
这里的问题是,虽然正常的 Fortran 语法允许调用 PrintName(JoeJohnson)
传递参数的实际类型似乎是(在 printname 中设置断点并编译 gfortran)
Breakpoint 1, modsimpleclass::printname (a=...) at ./stack.f90:10
10 print *, a%Name
(gdb) ptype a
type = Type __class_modsimpleclass_Person_t
PTR TO -> ( Type person :: _data )
PTR TO -> ( Type __vtype_modsimpleclass_Person :: _vptr )
End Type __class_modsimpleclass_Person_t
而JoeJohnson
的类型是非指针类型。我猜上面的类型是 gfortran 在 Fortran 中传递类型参数的方式。
在上面的例子中
PrintName(&JoeJohnson)
可以工作,但是很麻烦..
编辑:
只是为了完成 - ifx/ifort 实际上似乎使用了一个指针来传递参数
(gdb) ptype a
type = PTR TO -> ( Type person
character*20 :: name
void :: printname(void)
End Type person )
这样做 call modsimpleclass::printname(&JoeJohnson)
将不再那么笨拙(GDB 在使用 ifx/ifort 编译时无法解析 PrintName)。我不确定是否可以以一种有意义的方式调整 gdb 以允许这种调用。由于参数处理和调用语法依赖于编译器。
我想调用一个函数,该函数将 Gnu 调试器 (gdb) 中的派生类型作为参数。我最终遇到了段错误。这是一个“最小”工作示例:
module modSimpleClass
type Person
character(len=20) :: Name
contains
procedure PrintName
end type
contains
subroutine PrintName(a)
class(Person) :: a
print *, a%Name
end subroutine
subroutine Print42()
print *, "42"
end subroutine
subroutine PrintNameFromOutside(a)
class(Person) :: a
print *, a%Name
end subroutine
end module
program testgdb
use modSimpleClass
implicit none
type(Person) :: JoeJohnson
JoeJohnson%Name = "Joe Johnson"
call JoeJohnson%PrintName
end program testgdb
我用 gfortran 版本 9.3.0 编译它,运行 从 gdb 编译它并在结束前停止它。 以下内容有效:
call Print42()
print JoeJohnson%Name
以下内容不起作用:
call JoeJohnson%PrintName()!There is no member named PrintName.
call PrintName(JoeJohnson)!Error then segfault
call PrintNameFromOutside(JoeJohnson)!Error then segfault
错误如下:
The program being debugged was signaled while in a function called from GDB. GDB remains in the frame where the signal was received. To change this behavior use "set unwindonsignal on". Evaluation of the expression containing the function (modsimpleclass::printname) will be abandoned. When the function is done executing, GDB will silently stop.
如何从gdb正确调用fortran子程序?
感谢@Flusslauf 的回复。我将尝试重新表述您所说的话:
从 gfortran 的角度来看,如果我们在模块 modsimpleclass
中定义派生类型 Person
,
- 只有初始化变量的作用域才能看到原始类型。
- 任何以参数为参数的函数或子程序
该派生类型的对象看到类型
__class_modsimpleclass_Person_t
具有属性:_data
: 指向对象的指针。_vptr
:指向包含对象信息的指针。
所以函数实际上为派生类型的每个对象使用两个指针:一个指向对象 另一个指向有关对象的信息。
在 gdb 中,将指向对象的指针传递给函数, 但是传递给它的对象本身不起作用。
@Flusslauf 成立
call PrintName( &JoeJohnson )!works because it is equivalent to
call PrintName( a%_data )!this, which works too
call PrintName( a )!this works and it makes sense
call PrintName( a%_data, a%_vptr )!this also works
call PrintName( a%_vptr)!this outputs something strange
call PrintName( *(a%_data) )!causes segfault since equivalent to
call PrintName( JoeJohnson )!Error then segfault
,其中每条指令都在变量的正确范围内执行。
这里的问题是,虽然正常的 Fortran 语法允许调用 PrintName(JoeJohnson)
传递参数的实际类型似乎是(在 printname 中设置断点并编译 gfortran)
Breakpoint 1, modsimpleclass::printname (a=...) at ./stack.f90:10
10 print *, a%Name
(gdb) ptype a
type = Type __class_modsimpleclass_Person_t
PTR TO -> ( Type person :: _data )
PTR TO -> ( Type __vtype_modsimpleclass_Person :: _vptr )
End Type __class_modsimpleclass_Person_t
而JoeJohnson
的类型是非指针类型。我猜上面的类型是 gfortran 在 Fortran 中传递类型参数的方式。
在上面的例子中
PrintName(&JoeJohnson)
可以工作,但是很麻烦..
编辑:
只是为了完成 - ifx/ifort 实际上似乎使用了一个指针来传递参数
(gdb) ptype a
type = PTR TO -> ( Type person
character*20 :: name
void :: printname(void)
End Type person )
这样做 call modsimpleclass::printname(&JoeJohnson)
将不再那么笨拙(GDB 在使用 ifx/ifort 编译时无法解析 PrintName)。我不确定是否可以以一种有意义的方式调整 gdb 以允许这种调用。由于参数处理和调用语法依赖于编译器。