从 C++ 拦截 Fortran STOP

2023-12-12

我准备了一个与旧版 Fortran 库的 C++ 接口。

遗留库中的一些子例程遵循丑陋但可用的状态代码约定来报告错误,并且我使用此类状态代码从我的 C++ 代码中抛出可读的异常:它工作得很好。

另一方面,有时遗留库会调用STOP(终止程序)。即使病情可以恢复,它也经常这样做。

我想capture this STOP从 C++ 内部,到目前为止我还没有成功。

下面的代码很简单,但准确地代表了当前的问题:

Fortran 遗留库fmodule.f90:

module fmodule
  use iso_c_binding
  contains
    subroutine fsub(x) bind(c, name="fsub")
      real(c_double) x
      if(x>=5) then 
         stop 'x >=5 : this kills the program'
      else
         print*, x
      end if
    end subroutine fsub    
end module fmodule

C++ 接口main.cpp:

#include<iostream>

// prototype for the external Fortran subroutine
extern "C" {
  void fsub(double& x);  
}

int main() {  
  double x;
  while(std::cin >> x) {
    fsub(x);
  }
  return 0;
}

编译行(GCC 4.8.1 / OS X 10.7.4;$表示命令提示符):

$ gfortran -o libfmodule.so fmodule.f90 -shared  -fPIC -Wall
$ g++ main.cpp -L. -lfmodule -std=c++11

The run:

$ ./a.out 
1
   1.0000000000000000     
2
   2.0000000000000000     
3
   3.0000000000000000     
4
   4.0000000000000000     
5
STOP x >=5 : this kills the program

我怎样才能捕捉到STOP比如说,请求另一个号码。请注意,我不想碰 Fortran 代码.

我尝试过的:

  • std::atexit:一旦我进入它就无法从中“回来”
  • std::signal: STOP似乎没有发出我可以捕获的信号

您可以通过拦截对以下内容的调用来解决您的问题exit来自 Fortran 运行时的函数。见下文。a.out是用您的代码和您提供的编译行创建的。

步骤 1. 找出调用了哪个函数。火起来gdb

$ gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
[...]
(gdb) break fsub
Breakpoint 1 at 0x400888
(gdb) run
Starting program: a.out 
5

Breakpoint 1, 0x00007ffff7dfc7e4 in fsub () from ./libfmodule.so
(gdb) step
Single stepping until exit from function fsub,
which has no line number information.
stop_string (string=0x7ffff7dfc8d8 "x >=5 : this kills the programfmodule.f90", len=30) at /usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c:67

So stop_string叫做。我们需要知道这个函数对应哪个符号。

步骤 2. 找到该名称的确切名称stop_string功能。它必须位于共享库之一中。

$ ldd ./a.out 
    linux-vdso.so.1 =>  (0x00007fff54095000)
    libfmodule.so => ./libfmodule.so (0x00007fa31ab7d000)
    libstdc++.so.6 => /usr/local/gcc/4.7.2/lib64/libstdc++.so.6 (0x00007fa31a875000)
    libm.so.6 => /lib64/libm.so.6 (0x0000003da4000000)
    libgcc_s.so.1 => /usr/local/gcc/4.7.2/lib64/libgcc_s.so.1 (0x00007fa31a643000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003da3c00000)
    libgfortran.so.3 => /usr/local/gcc/4.7.2/lib64/libgfortran.so.3 (0x00007fa31a32f000)
    libquadmath.so.0 => /usr/local/gcc/4.7.2/lib64/libquadmath.so.0 (0x00007fa31a0fa000)
    /lib64/ld-linux-x86-64.so.2 (0x0000003da3800000)

我在 fortran 运行时中找到了它(毫不奇怪)。

$ readelf -s /usr/local/gcc/4.7.2/lib64/libgfortran.so.3|grep stop_string
  1121: 000000000001b320    63 FUNC    GLOBAL DEFAULT   11 _gfortran_stop_string@@GFORTRAN_1.0
  2417: 000000000001b320    63 FUNC    GLOBAL DEFAULT   11 _gfortran_stop_string

步骤 3. 编写一个函数来替换该函数

我在源代码中寻找函数的精确签名(/usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c see gdb会议)

$ cat my_exit.c 
#define _GNU_SOURCE
#include <stdio.h>

void _gfortran_stop_string (const char *string, int len)
{
        printf("Let's keep on");
}

步骤 4. 编译导出该符号的共享对象。

gcc -Wall -fPIC -c -o my_exit.o my_exit.c
gcc -shared -fPIC -Wl,-soname -Wl,libmy_exit.so -o libmy_exit.so my_exit.o

步骤 5. 使用 LD_PRELOAD 运行程序,以便我们的新函数优先于运行时的函数

$ LD_PRELOAD=./libmy_exit.so ./a.out 
1
   1.0000000000000000     
2
   2.0000000000000000     
3
   3.0000000000000000     
4
   4.0000000000000000     
5
Let's keep on   5.0000000000000000     
6
Let's keep on   6.0000000000000000     
7
Let's keep on   7.0000000000000000   

就这样吧。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 C++ 拦截 Fortran STOP 的相关文章

  • 如何在 Visual Studio 2010 中增强 XAML 设计器?

    当我使用 XAML 设计器时 进入设计器和退出设计器是如此困难和缓慢 当我这样做时 Visual Studio 卡了一段时间 有什么方法可以增强 XAML 设计器和编辑器吗 Ant 保存 XAML 文件时非常慢 这通常意味着您可能有复杂的
  • VB.NET 相当于 C# 属性简写吗?

    是否有与 C 等效的 VB NET public string FirstName get set 我知道你能做到 Public Property name As String Get Return name ToString End Ge
  • 如何读取扩展文件属性/文件元数据

    因此 我按照教程使用 ASP net core 将文件 上传 到本地路径 这是代码 public IActionResult About IList
  • std::cout 和 std::wcout 有什么区别?

    在c 中 有什么区别std cout and std wcout 它们都控制流缓冲区的输出或将内容打印到控制台 或者它们只是相似吗 它们作用于不同的字符类型 std cout uses char作为字符类型 std wcout uses w
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 推导指南中的引用和值之间的差异

    考虑类型A template
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 如何从 .resx 文件条目获取注释

    资源文件中的字符串有名称 值和注释 The ResXResourceReader类让我可以访问名称和值 有办法看评论吗 你应该能够得到Comment via ResXDataNode class http msdn microsoft co
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • 关于在 Windows 上使用 WiFi Direct Api?

    我目前正在开发一个应用程序 我需要在其中创建链接 阅读 无线网络连接 在桌面应用程序 在 Windows 10 上 和平板电脑 Android 但无关紧要 之间 工作流程 按钮 gt 如果需要提升权限 gt 创建类似托管网络的 WiFi 网
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 使用 JNI 从 Java 代码中检索 String 值的内存泄漏

    我使用 GetStringUTFChars 从使用 JNI 的 java 代码中检索字符串的值 并使用 ReleaseStringUTFChars 释放该字符串 当代码在 JRE 1 4 上运行时 不会出现内存泄漏 但如果相同的代码在 JR
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • 有人可以提供一个使用 Amazon Web Services 的 itemsearch 的 C# 示例吗

    我正在尝试使用 Amazon Web Services 查询艺术家和标题信息并接收回专辑封面 使用 C 我找不到任何与此接近的示例 所有在线示例都已过时 并且不适用于 AWS 的较新版本 有一个开源项目CodePlex http www c
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • 使用 GROUP 和 SUM 的 LINQ 查询

    请帮助我了解如何使用带有 GROUP 和 SUM 的 LINQ 进行查询 Query the database IEnumerable

随机推荐