如何从R会话中更改C宏变量(预处理器定义指令)?

b_r*_*on_ 6 c r directive system

问题

  1. 从R会话内部编译共享库system()或使用shell()它们动态加载它们是不好的做法吗?
  2. 是否有一种"更好"的方式(比下面的代码)根据来自R会话的用户输入更改C源文件中的宏变量的值?

背景

目的

在R会话中,我想创建一个函数

  1. 更改模板C源文件中的宏变量的值,
  2. 为编辑后的源文件指定一个新名称,
  3. 编译新程序的共享库,和
  4. 动态地将新共享库加载到当前R会话中

调用模板C源文件template.tmp,让它看起来像:

...
#define VAR
...
Run Code Online (Sandbox Code Playgroud)

(我不打算实际编译template.tmp,因此.tmp文件扩展名.我只是用它作为模板创建其他源文件,只有#define指令发生变化.)

下面是我创建的R函数,用于执行上述步骤.为简单起见,我删除了代码行,这些代码声明了正确的路径名,或者为Windows和其他类似的Unix添加了可移植性.

myfunc <- function(val){
  # create commands for system()
  subst_cmd <- paste0("sed 's/define VAR/define VAR ", val, "/' template.tmp > newprog.c")
  shlib_cmd <- paste0("R CMD SHLIB newprog.c")

  # submit commands to system()
  system(subst_cmd)
  system(shlib_cmd)

  # dynamically load shared library
  dyn.load(newprog.so)
}
Run Code Online (Sandbox Code Playgroud)

因此,myfunc(12345)将使用以下行创建新的C源文件,并将其编译为共享库并将其动态加载到当前R会话中.

...
#define VAR 12345
...
Run Code Online (Sandbox Code Playgroud)

动机

我有一个功能,其中速度非常重要,因为该功能可以被调用数千次.与使用#define预处理程序指令相比,将值传递给C源文件中的函数会极大地降低速度.我的想法是如何在R中编辑文件然后编译它并将其加载到R会话中.但我不知道这是不是很好的做法,还是有另一种方法可以完成同样的任务.我已遇到的一个问题发生在我远程进入计算机集群时,其中登录节点具有编译功能但计算节点没有.

Rav*_*ave 1

免责声明:我对 R 没有太多了解。我用我使用 C 共享库的经验来回答这个问题。

使用 system() 或 shell() 从 R 会话内部编译共享库然后动态加载它们是一种不好的做法吗?

是的,这不是一个好的做法。正如你所说,每次更改文件和编译可能需要花费 1000 秒的时间,这不是一个好的选择。

是否有一种“更好”的方法(比下面的代码)可以根据 R 会话的用户输入更改 C 源文件中宏变量的值?

如果唯一的要求是更改宏的值,那么为什么不将其转换为变量并在动态加载库中调用函数时传递该变量呢?

考虑以下示例:(下面的代码用于动态库)

foo.h

#ifndef foo_h__
#define foo_h__

extern void foo(int var);

#endif  // foo_h__
Run Code Online (Sandbox Code Playgroud)

foo.c

#include <stdio.h>
int global_var;

void foo(int var)
{
    global_var= var;
}
Run Code Online (Sandbox Code Playgroud)

通过将 var 的所需值传递给 foo 函数,从 R 调用上述函数。(我希望你知道该怎么做)

我不打算实际编译 template.tmp,因此使用 .tmp 文件扩展名。我只是使用它作为模板来创建其他源文件,其中仅 #define 指令发生更改。

我建议不要这样做。即使您有多个这样的宏,您仍然可以使用上述逻辑来处理它。我的建议是编译一次库,然后调用初始化函数(上面示例中的 foo),向其传递所需的值。这也将避免多次加载库,从而提高其效率。这比您当前所做的更好,并且易于维护和记录。

如果您关心速度和效率,文件操作本质上会很慢。您的程序有一天可能会变得很大,因此为每个函数调用编译它会进一步增加执行延迟。每次都编译库是个坏主意。