代码之家  ›  专栏  ›  技术社区  ›  jsight TaherT

来自c的r-最简单的可能helloworld

  •  18
  • jsight TaherT  · 技术社区  · 14 年前

    启动r解释器、传递一个小表达式(如2+2)并得到结果的最简单的c函数是什么?我正试图用mingw在windows上编译。

    4 回复  |  直到 10 年前
        1
  •  10
  •   Shane    11 年前

    你想从C打电话给R吗?

    section 8.1 in the Writing R Extensions 手册。您还应该查看“tests”目录(下载源包提取它,您将拥有tests目录)。之前在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;
     }
    

    顺便说一句,您可能想考虑使用 里内 相反:德克提供 a nice "hello world" example 在项目主页上。

    如果你有兴趣从R打电话给C,我的原始答案是:

    这并不完全是“你好世界”,但这里有一些好的资源:

        2
  •  9
  •   Jeff    14 年前

    干得好。它是主要功能,但是您应该能够使它适应更通用的功能。本例从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
    
        3
  •  7
  •   Simon Urbanek    13 年前

    我认为以上任何一个问题都没有回答这个问题——这个问题是评估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);
    
        4
  •  4
  •   JD Long    14 年前

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

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

    它会为你打印“你好,世界”。你甚至不知道编译器和链接器被调用的位置/方式/时间。[r\nilvalue是r的空版本sexp和 .Call() 这里使用的签名要求您返回一个sexp——请参阅“编写r扩展”手册,这是您在这里无法避免的。]

    然后,将这些代码打包。我们在使用 内联的 对于 Rcpp 单元测试(超过200个,现在开始计算)和一些例子。

    哦,还有这个 内联的 这个例子适用于任何操作系统。即使是windoze,只要你安装了r包构建工具链,在路径等pp。

    编辑: 我看错了这个问题。你想要的基本上是 littler 前端(使用纯c)和 RInside C++中的类因子。

    杰夫和我从不费心移植 利特勒 去温多兹,但是 里内 在最近的版本中确实在那里工作过。因此,您应该能够查看构建配方并创建 里内 以便可以将表达式馈送到嵌入式r进程。我想你还是想 RCPP 否则会变得很乏味。

    编辑2: 正如shane提到的,在tests/embedding/和makefile.win中的r源代码中确实有一些例子。如果你愿意了解r的内部结构,也许这是最简单的开始。