About me | pbdR Tech | HPSC | Phyloclustering | R_note |

R_note -- The Exploration of Statistical Software R (統計軟體 R 深度歷險)
About R_note
Reference
MS Windows

Batch jobs
Function
Data/MySQL
Plot
String/Parse

Remark Lines
Classes/S3
S4 Methods
Batch more
Environment

Good Coding
Fast Loop
LAM/MPI/Rmpi
Recursion

PHP Call R
Basic C
R Call Fortran/C
R Call GSL
C Call R API
C Call R Objects
Standalone

Make Packages
C Pointer
Debug




Section: C Call R Objects

  • Reference
    Read the web page The R Manuals
    PDF document Writing R Extensions (Chapter 5) in The R Manuals (my mirror here).
    Sigal Blay's web space (my mirror here).

  • Steps
    1. In R, there are two methods to directly pass the R objects to C, .Call() and .External().
    2. In C, there are two methods to handle R objects by including "Rdefines.h" and "Rinternals.h" as the header files.
    3. R objects use a structure type SEXP as a pointer in C.
      1. Allocate R objects.
      2. Protect R objects.
      3. Duplicate Objects passed from R if any modification is required.
        Any objects passed from R should be read-only.
      4. After any computing, copy the results to R objects.
      5. Unprotect R objects.
    4. Return R objects to R from C.

    At the following, only .Call() and "Rinternals.h" are demonstrated and R's list and array will be passed to C.

  • Example 1
    Available C file: "callRobj.c".
    This is a poisoned vitamin C example discussed with Dr. Karin S. Dorman for modifing a C pointer permanently inside an internal function. Also, an R "list" object is allocated in C. This object store and return a modified version of input to R.
        
    #include <R.h>
    #include <Rinternals.h>
    
    void vitamin_c(SEXP R_n, int **C_n){
        *C_n = INTEGER(R_n);
    }
    
    SEXP poison(SEXP R_n){
        int i, *C_n_1, *C_n_2;
        double *C_new_1, *C_new_2;
        SEXP new_1, new_2, ret, ret_names;
        char *names[2] = {"new.1", "new.2"};
    
        /* Both have the same results. */
        vitamin_c(R_n, &C_n_1);
        C_n_2 = INTEGER(R_n);
    
        /* protect R objects in C. */
        PROTECT(new_1 = allocVector(REALSXP, 1));
        PROTECT(new_2 = allocVector(REALSXP, 1));
        PROTECT(ret = allocVector(VECSXP, 2));
        PROTECT(ret_names = allocVector(STRSXP, 2));
      
        /* set a list object for R. */
        SET_VECTOR_ELT(ret, 0, new_1);
        SET_VECTOR_ELT(ret, 1, new_2);
    
        /* set list's names for R. */
        for(i = 0; i < 2; i++){
          SET_STRING_ELT(ret_names, i, mkChar(names[i])); 
        }
        setAttrib(ret, R_NamesSymbol, ret_names);
    
        /* assign points to R objects. */
        C_new_1 = REAL(new_1);
        C_new_2 = REAL(new_2);
    
        /* update for return to R. */
        *C_new_1 = (double) (*C_n_1 + 1);
        *C_new_2 = (double) (*C_n_2 + 1);
      
        /* unprotect for R. */
        UNPROTECT(4);
        return(ret);
    }
    


  • Outputs
        
    > a <- 1
    > ret <- .Call("poison", as.integer(a))
    > ret
    $new.1
    [1] 2
    
    $new.2
    [1] 2
    


  • Conclusion
    Call by address in C.
    Call by address in R when .Call() and .External() are used.

[ Go to top ]

Maintained: Wei-Chen Chen
E-Mail: wccsnow @ gmail.com
Last Revised: Dec 12 2016, 09:44 (CST Taipei, Taiwan)
Created: Oct 06 2003
free counters Best Resolution
IE6.0
1280x1024
small font