R调用C程序 7

R是一个不错的脚本程序,每写一行代码都可以看到实时的输出结果。但是,它有一个很大的问题,就是在运行循环时效率太低。所以当大运算量的程序在R当中运行就显得非常的缓慢。解决办法就是将大运算量的部分交给其它语言去做,比如说C,我个人比较习惯用c/c++)。
下面就是一个非常简单的例子,教你如何用R来调用C中的程序。

首先打开一个文本编辑器,写下下面的代码:

/*
 *  test.c
 *  
 *
 *  Created by Jianhong Ou on 3/21/12.
 *  Copyright 2012 糗世界(qiuworld.com). All rights reserved.
 *
 */
#include <R.h>
#include <Rmath.h>
 
void add(double *a,double *b,int n,double *c){
	*c=*a+*b;
}
 
void hello(int *n){
	int i;
	for (i=0; i< *n; i++) {
		Rprintf("Hello, world!\n");
	}
}

把它保存成test.c文件。其中,include了两个头文件,一个是R.h,一个是Rmath.h。前者是必须的,所有一切需要R调用的C程序都应该加上这一头文件。至于Rmath.h一般也是需要的,因为毕竟是用C来运算的,不可能只是写个hello world这个样子。可以注意到,原本的printf变成了Rprintf。这只是将printf的输出改成了R console而已。

接下来的一步是在terminal或者command当中运行命令,把c程序编译出来。

$ R CMD SHLIB test.c
gcc -arch x86_64 -std=gnu99 -I/Library/Frameworks/R.framework/Resources/include -I/Library/Frameworks/R.framework/Resources/include/x86_64  -I/usr/local/include    -fPIC  -g -O2 -c test.c -o test.o
gcc -arch x86_64 -std=gnu99 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/usr/local/lib -o test.so test.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation

这时,你就可以在当前目录下看到test.o和test.so文件了。有一点我们需要注意的是,该命令会自己加上一些参数,比如说-arch等等。一般不需要修改。如果你需要修改,比如说输出的动态链接文件你希望是hello.so那你需要运行R CMD SHLIB -o hello.so test.c

接下来的工作就是进入R。注意,因为例子是x86_64体系下编译的,所以需要进入64位的R.在R当中,使用setwd设置工作目录为test.so所在的目录。而后运行

> dyn.load("test.so")
> .C("hello",as.integer(3))
Hello, world!
Hello, world!
Hello, world!
[[1]]
[1] 3

成功!!等等,我们看到最后怎么出现了

[[1]]
[1] 3

这是R调用C程序后会将所有的输入参数再回传回来。这一点非常重要。因为在整个调用过程中,c程序return的结果都会被抛弃,我们无法接受return回来的结果,只能通过传入参数地址来获得计算结果。所以,我们可以将C程序中所有的程序都写成void程序,然后通过传过一个地址来回收运算结果。例子中的add就是了。

> .C("add",as.double(2),as.double(5),as.double(0.0))
[[1]]
[1] 2
 
[[2]]
[1] 5
 
[[3]]
[1] 7
 
> .C("add",as.double(2),as.double(5),as.double(0.0))[[3]]
[1] 7
> add<-function(a,b){.C("add",as.double(a),as.double(b),as.double(0.0))[[3]]}
> add(2,3)
[1] 5

7 thoughts on “R调用C程序

  1. Pingback: R当中调用C/C++ | 糗世界

  2. Reply cs_test 5月 22,2013 1:13 上午

    这条语句
    .C(“add”,as.double(2),as.double(5),as.double(0.0))

    我的结果是
    > .C(“add”,as.double(2),as.double(5),as.double(0.0))
    [[1]]
    [1] 2

    [[2]]
    [1] 5

    [[3]]
    [1] 0

    和你的不一样,不知道怎么样才能得到你的结果?

  3. Reply 小橘 7月 1,2014 6:24 上午

    你好,
    请问有什么方法可以在R中查看C的源码?
    谢谢。

  4. Reply 请叫我雷……锋…… 5月 17,2017 4:05 上午

    在test.c中有个小错误,导致
    > .C(“add”,as.double(2),as.double(5),as.double(0.0))
    [[1]]
    [1] 2

    [[2]]
    [1] 5

    [[3]]
    [1] 0

    错误在:
    void add(double *a,double *b,int n,double *c){
    *c=*a+*b;
    }
    把int n,删掉,就会得到正确的答案!

Leave a Reply

  

  

  

%d 博主赞过: