【问题标题】:R from C -- Simplest Possible HelloworldC 中的 R——最简单的 Helloworld
【发布时间】:2010-03-17 15:15:43
【问题描述】:

启动 R 解释器、传入一个小表达式(例如 2+2)并得到结果的最简单的 C 函数是什么?我正在尝试在 Windows 上使用 MingW 进行编译。

【问题讨论】:

  • 好点...澄清了。

标签: c windows r


【解决方案1】:

你想从 C 调用 R?

查看section 8.1 in the Writing R Extensions 手册。您还应该查看“测试”目录(下载源包解压缩它,您将拥有测试目录)。之前在 R-Help 和 here was the example 上提出了类似的问题:

#include <Rinternals.h> 
#include <Rembedded.h> 

SEXP hello() { 
  return mkString("Hello, world!\n"); 
} 

int main(int argc, char **argv) { 
  SEXP x; 
  Rf_initEmbeddedR(argc, argv); 
  x = hello(); 
  return x == NULL;             /* i.e. 0 on success */ 
} 

R 手册中的简单示例如下:

 #include <Rembedded.h>

 int main(int ac, char **av)
 {
     /* do some setup */
     Rf_initEmbeddedR(argc, argv);
     /* do some more setup */

     /* submit some code to R, which is done interactively via
         run_Rmainloop();

         A possible substitute for a pseudo-console is

         R_ReplDLLinit();
         while(R_ReplDLLdo1() > 0) {
           add user actions here if desired
         }
      */
     Rf_endEmbeddedR(0);
     /* final tidying up after R is shutdown */
     return 0;
 }

顺便说一句,您可能需要考虑使用 Rinside:Dirk 在项目主页上提供了a nice "hello world" example

如果您有兴趣从 R 调用 C,这是我的原始答案:

这并不完全是“hello world”,但这里有一些很好的资源:

【讨论】:

  • 非常感谢...我错过了 R init 函数调用...哎呀。你(和其他人)的例子非常有帮助(太糟糕了,我也不能给其他一些人接受的答案......:))。
【解决方案2】:

给你。它是主要功能,但您应该能够将其调整为更通用的功能。此示例从 C 调用和 C 字符串构建 R 表达式。在 windows 上编译是你自己的事,但我在 linux 上提供了编译步骤:

 /* simple.c */
 #include <Rinternals.h>
 #include <Rembedded.h>
 #include <R_ext/Parse.h>
 int
 main(int argc, char *argv[])
 {
    char *localArgs[] = {"R", "--no-save","--silent"};
    SEXP e, tmp, ret;
    ParseStatus status;
    int i;

    Rf_initEmbeddedR(3, localArgs);

    /* EXAMPLE #1 */

    /* Create the R expressions "rnorm(10)" with the R API.*/
    PROTECT(e = allocVector(LANGSXP, 2));
    tmp = findFun(install("rnorm"), R_GlobalEnv);
    SETCAR(e, tmp);
    SETCADR(e, ScalarInteger(10));

    /* Call it, and store the result in ret */
    PROTECT(ret = R_tryEval(e, R_GlobalEnv, NULL));

    /* Print out ret */
    printf("EXAMPLE #1 Output: ");
    for (i=0; i<length(ret); i++){
        printf("%f ",REAL(ret)[i]);
    }
    printf("\n");

    UNPROTECT(2);


    /* EXAMPLE 2*/

    /* Parse and eval the R expression "rnorm(10)" from a string */
    PROTECT(tmp = mkString("rnorm(10)"));
    PROTECT(e = R_ParseVector(tmp, -1, &status, R_NilValue));
    PROTECT(ret = R_tryEval(VECTOR_ELT(e,0), R_GlobalEnv, NULL));

    /* And print. */
    printf("EXAMPLE #2 Output: ");
    for (i=0; i<length(ret); i++){
        printf("%f ",REAL(ret)[i]);
    }
    printf("\n");

    UNPROTECT(3);
    Rf_endEmbeddedR(0);
    return(0);
 }

编译步骤:

$ gcc -I/usr/share/R/include/ -c -ggdb simple.c
$ gcc -o simple simple.o  -L/usr/lib/R/lib -lR
$ LD_LIBRARY_PATH=/usr/lib/R/lib R_HOME=/usr/lib/R ./simple
EXAMPLE #1 Output: 0.164351 -0.052308 -1.102335 -0.924609 -0.649887 0.605908 0.130604 0.243198 -2.489826 1.353731
EXAMPLE #2 Output: -1.532387 -1.126142 -0.330926 0.672688 -1.150783 -0.848974 1.617413 -0.086969 -1.334659 -0.313699

【讨论】:

  • 可以在VS2008(MS编译器)下编译吗?论据是什么?
【解决方案3】:

我认为以上任何一个都没有回答这个问题 - 这是评估 2 + 2 ;)。使用字符串表达式类似于:

#include <Rinternals.h>
#include <R_ext/Parse.h>
#include <Rembedded.h>

int main(int argc, char **argv) {
    SEXP x;
    ParseStatus status;
    const char* expr = "2 + 2";

    Rf_initEmbeddedR(argc, argv);

    x = R_ParseVector(mkString(expr), 1, &status, R_NilValue);
    if (TYPEOF(x) == EXPRSXP) { /* parse returns an expr vector, you want the first */
        x = eval(VECTOR_ELT(x, 0), R_GlobalEnv);
        PrintValue(x);
    }

    Rf_endEmbeddedR(0);

    return 0;
}

这显然缺少错误检查,但有效:

Z:\>gcc -o e.exe e.c -IC:/PROGRA~1/R/R-213~1.0/include -LC:/PROGRA~1/R/R-213~1.0/bin/i386 -lR
Z:\>R CMD e.exe
[1] 4

(要为您的 R 获取正确的命令,请使用 R CMD SHLIB e.c,它会为您提供相关的编译器标志)

如果表达式足够简单,您也可以手动构建表达式 - 例如,您可以使用 rnorm(10)

SEXP rnorm = install("rnorm");
SEXP x = eval(lang2(rnorm, ScalarInteger(10)), R_GlobalEnv);

【讨论】:

  • 可以在Visual Studio下编译(MS编译器)吗?参数是什么?
  • 不,VC不官方支持,原生编译器是MinGW。可能有一些方法可以将 VC 代码与 R 结合起来(例如,通过 DLL),但不能保证可以工作。
  • 我已经在 Visual Studio (MS Compiler) 下编译了代码:)。为此,应手动创建 R.lib 库。
【解决方案4】:

我认为你不能比inline 包(它支持 C、C++ 和 Fortran)做得更好:

library(inline)
fun <- cfunction(signature(x="ANY"), 
                 body='printf("Hello, world\\n"); return R_NilValue;')
res <- fun(NULL)

它将为您打印“Hello, World”。而且您甚至不知道在哪里/如何/何时调用编译器和链接器。 [ R_NilValue 是 R 的 SEXP 的 NULL 版本,这里使用的.Call() 签名要求您返回一个 SEXP——请参阅此处无法避免的“编写 R 扩展”手册。 ]

然后,您将获取此类代码并将其包装在一个包中。我们在使用方面取得了巨大成功 inlineRcpp 单元测试(超过 200 个,现在还在增加)和一些示例。

哦,这个inline 示例适用于任何操作系统。甚至 Windoze 也提供您在 PATH 等 pp 中安装了 R 包构建工具链。

编辑:我误读了这个问题。您想要的本质上是 littler 前端所做的(使用纯 C)以及 RInside 类为 C++ 分解的内容。

Jeff 和我从未将 littler 移植到 Windoze,但 RInside 在最近的版本中确实在那里工作。因此,您应该能够探索构建配方并创建 RInside 的纯 C 变体,以便您可以将表达式提供给嵌入式 R 进程。我怀疑你仍然想要Rcpp 之类的东西作为线索,否则它会变得乏味。

编辑 2: 正如 Shane 所提到的,在测试/嵌入/中的 R 源代码中确实有一些示例以及 Makefile.win。如果您愿意了解 R 的内部结构,这可能是最简单的开始。

【讨论】:

  • 没错,但那是 C++……我现在更喜欢 C 示例。不过,Rcpp 看起来非常易于使用。
  • 是的,我进行了相应的编辑。内联在没有 Rcpp 的情况下工作正常。但是一旦你真的想交换数据,我会选择 Rcpp,即使你可能会觉得 C++ 比 C 更复杂。不一定非得如此。
  • 这很有趣,但与我所寻找的相反。我有兴趣从(可能是遗留的)C 代码调用 R,而不是反过来......如果最初的问题不清楚,我很抱歉。不过,此信息也很有帮助。 :)
  • 哦,我误会了。在这种情况下,试试“littler”和“RInside”,我会修改我的答案。
猜你喜欢
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多