簡體   English   中英

是否有可能在R(或使用Rprintf())中“抓取”/“刮”C printf()的.Call()輸出?

[英]Is it possible to “grab”/“scrape” the .Call() output of C printf() within R (or with Rprintf())?

我正在使用R代碼,它通過.Call()與C接口。 C函數通過printf()輸出到STDOUT。 作為一個具體的,更簡單的例子,我將關注http://mazamascience.com/WorkingWithData/?p=1099

這是我們的C代碼,通過printf()helloA1.c輸出hello world:

#include <R.h>
#include <Rdefines.h>
#include <stdio.h>
SEXP helloA1() {
  printf("Hello World!\n");
  return(R_NilValue);
}

通過R CMD SHLIB helloA1.c安裝后,我們在R中調用如下函數:

> dyn.load("helloA1.so")
> hellocall = .Call("helloA1")
  Hello World!

我無法訪問“Hello World!”文本。 但是在R中作為數據結構。 例如

> vec1 = as.vector( .Call("helloA1"))
Hello World!
> vec1
NULL
> 

要么

> library(data.table)
> dt = as.data.table(.Call("helloA1"))
Hello World!
> dt
Null data.table (0 rows and 0 cols)
> 

有沒有辦法將printf()的輸出“加載”到R?

我可以將函數轉換為Rcpp,但是我會遇到與Rprintf()相同的問題。

編輯:抱歉,我以前以為RPrintf()是內部的功能Rcpp 我已恰當地編輯了這個問題的標題。

所以,這里的問題是printf否定了R的內置輸出收集機制。 特別是,沒有C級“stdout”文件流,因此,在Rgui或RStudio中沒有要收集的輸出。 有關詳細信息,請參見第6.5節寫入R擴展的 打印

兩種可能的解決方

  1. 定義一個宏,將printf設置為Rprintf並包含#define STRICT_R_HEADERS以避免錯誤
  2. 在違規代碼Rprintf printf實例切換為Rprintf

從這里開始,捕獲可以傳遞給capture.output() ,它直接將輸出分配給變量,或者傳遞給sink() ,它將輸出重定向到一個文件,然后必須使用readLines()讀回其內容。 后者使得可以在多行代碼上清楚地封閉以捕獲輸出,而先前關注於確保輸入表達式中存在的輸出。

選項1

對於第一次迭代,只需定義包含自定義定義的頭,然后包含第三方庫,例如

my_code.h

#ifndef MY_CODE_H
#define MY_CODE_H
#include <R.h>
// this load R_ext/Print.h.

// #include <YOUR_LIBRARY.h>

// Define strict headers
#define STRICT_R_HEADERS
// Map printf to Rprintf
#define printf Rprintf
#endif

toad.c

#include <R.h>
#include <Rdefines.h>
#include "my_code.h"

SEXP helloA1() {
  printf("Hello World!\n");
  return(R_NilValue);
}

toad_example.R

system("R CMD SHLIB ~/Desktop/toad.c")
dyn.load("~/Desktop/toad.so")

helloA1 <- function() {
  result <- .Call("helloA1")
}

# Gregor's suggestion
captured_data = capture.output(helloA1())

# Using sink around multiple function calls to redirect output
# to a single file
sink("sink-examp.txt")
helloA1()
sink()

input_data = readLines("sink-examp.txt")

all.equal(input_data, captured_data)
# [1] TRUE

我在R包中實現了這種方法,可以在這里找到:

https://github.com/coatless/printf2Rprintf

選項2

此選項手動重新定義printf函數。

toad.c

#include <R.h>
#include <Rdefines.h>
SEXP helloA1() {
  Rprintf("Hello World!\n"); // manually changed
  return(R_NilValue);
}

toad_example.R

system("R CMD SHLIB ~/Desktop/toad.c")
dyn.load("~/Desktop/toad.so")

helloA1 <- function() {
  result <- .Call("helloA1")
}

# Gregor's suggestion
captured_data = capture.output(helloA1())

# Using sink around multiple function calls to redirect output
# to a single file
sink("sink-examp.txt")
helloA1()
sink()

input_data = readLines("sink-examp.txt")

all.equal(input_data, captured_data)
# [1] TRUE

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM