如何从C代码发出R异常信号

时间:2015-02-21 23:15:18

标签: c r

可以使用列表对象调用R中的stop函数,以便发出特定类型的异常信号。例如,要发出foo异常信号,我们可以这样做:

foo <- list (
  message = "my foo error"
)
class(foo) <- c("foo", "condition")

tryCatch (
  stop(foo), 
  foo = function(e){"never mind foo."}
)

C代码是否有用于执行此操作的接口(表示自定义异常)? Rf_error仅允许引发一般错误,但不允许指定异常类。

2 个答案:

答案 0 :(得分:2)

如何在C ++中执行此操作的标准示例是in this Rcpp Gallery post

只用第一部分进行一次小编辑:

#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
double takeLog(double val) {
    try {
        if (val <= 0.0) {           // log() not defined here
            throw std::range_error("Inadmissible value");
        }
        return log(val);
    } catch(std::exception &ex) {   
        forward_exception_to_r(ex);
    } catch(...) { 
        stop("c++ exception (unknown reason)"); 
    }
    return NA_REAL;             // not reached
}

按预期工作:

R> sourceCpp("/tmp/ex.cpp")
R> takeLog(-1)
Error: Inadmissible value
R> 

该帖子的其余部分有一些细节。

答案 1 :(得分:2)

基于上面的建议,我写了这个功能,它可以满足我的需要:

void signal_exception(const char* message, const char* condition){
  //the condition object
  SEXP vec = PROTECT(allocVector(VECSXP, 1));
  SET_VECTOR_ELT(vec, 0, mkString(message));
  setAttrib(vec, R_NamesSymbol, mkString("message"));

  //the class vector
  SEXP cls = PROTECT(allocVector(STRSXP, 3));
  SET_STRING_ELT(cls, 0, mkChar(condition));
  SET_STRING_ELT(cls, 1, mkChar("error"));
  SET_STRING_ELT(cls, 2, mkChar("condition"));
  setAttrib(vec, R_ClassSymbol, cls);

  //signal the condition by calling base::stop
  SEXP stop_sym  = PROTECT(Rf_install("stop"));
  SEXP call = PROTECT(Rf_lang2(stop_sym, vec));
  UNPROTECT(4);
  Rf_eval(call, R_GlobalEnv);
}

它基本上使用第二个参数推广Rf_error,您可以使用它来指定错误的类。

我不认为从C调用base::stop是非常优雅的,只是让它回调.Internal(.signalCondition())但我看起来目前没有用于直接通知来自条件的API C.