c - 了解如何在 R 中处理 .Internal C 函数

标签 c r syntax internals

我想知道是否有人可以向我说明 R 如何从控制台提示符下键入的 R 命令执行 C 调用。 R 对 a) 函数参数和 b) 函数调用本身的处理让我特别困惑。

让我们举个例子,在这个例子中是 set.seed()。想知道它是如何工作的我在提示符下输入名称,获取源代码(look here for more on that),看到最终有一个 .Internal(set.seed(seed, i.knd, normal.kind),所以尽职尽责地在/src/names.c.Internals部分查找相关的函数名,发现它叫做do_setseed和在 RNG.c 中,它引导我...

SEXP attribute_hidden do_setseed (SEXP call, SEXP op, SEXP args, SEXP env)
{
    SEXP skind, nkind;
    int seed;

    checkArity(op, args);
    if(!isNull(CAR(args))) {
    seed = asInteger(CAR(args));
    if (seed == NA_INTEGER)
        error(_("supplied seed is not a valid integer"));
    } else seed = TimeToSeed();
    skind = CADR(args);
    nkind = CADDR(args);
    //...
      //DO RNG here 
    //...
    return R_NilValue;
}
  • 什么是CARCADRCADDR?我的研究使我相信它们是受 Lisp 影响的关于列表的构造,但除此之外我不明白这些函数的作用或为什么需要它们
  • checkArity() 做什么?
  • SEXP args 似乎不言自明,但这是一个列表 在函数调用中传递的参数?
  • SEXP op 代表什么?我将其理解为运算符(如 + 等二元函数),但 SEXP 调用 的用途是什么?

有人能理解我打字时发生的事情吗

set.seed(1)

在 R 控制台提示符下,到定义 skindnkind 的那一点?我发现我无法很好地理解这个级别的源代码以及从解释器到 C 函数的路径。

最佳答案

CARCDR 是您访问配对列表对象的方式,如 section 2.1.11 of R Language Definition 中所述。 . CAR 包含第一个元素,CDR 包含其余元素。 section 5.10.2 of Writing R Extensions 中给出了示例:

#include <R.h>
#include <Rinternals.h>

SEXP convolveE(SEXP args)
{
    int i, j, na, nb, nab;
    double *xa, *xb, *xab;
    SEXP a, b, ab;

    a = PROTECT(coerceVector(CADR(args), REALSXP));
    b = PROTECT(coerceVector(CADDR(args), REALSXP));
    ...
}
/* The macros: */
first = CADR(args);
second = CADDR(args);
third = CADDDR(args);
fourth = CAD4R(args);
/* provide convenient ways to access the first four arguments.
 * More generally we can use the CDR and CAR macros as in: */
args = CDR(args); a = CAR(args);
args = CDR(args); b = CAR(args);

还有一个 TAG 宏来访问给实际参数的名称。

checkArity 确保传递给函数的参数数量是正确的。 args 是传递给函数的实际参数。 op 是“用于处理多个 R 函数的 C 函数”的偏移指针(引用自 src/main/names.c,其中还包含显示每个函数的偏移量和元数)。

例如,do_colsum 处理 col/rowSumscol/rowMeans

/* Table of  .Internal(.) and .Primitive(.)  R functions
 * =====     =========        ==========
 * Each entry is a line with
 *
 *  printname  c-entry     offset  eval  arity   pp-kind   precedence  rightassoc
 *  ---------  -------     ------  ----  -----   -------   ----------  ----------
{"colSums",    do_colsum,  0,      11,   4,     {PP_FUNCALL, PREC_FN,  0}},
{"colMeans",   do_colsum,  1,      11,   4,     {PP_FUNCALL, PREC_FN,  0}},
{"rowSums",    do_colsum,  2,      11,   4,     {PP_FUNCALL, PREC_FN,  0}},
{"rowMeans",   do_colsum,  3,      11,   4,     {PP_FUNCALL, PREC_FN,  0}},

请注意,上表中的 arity 是 4,因为(尽管 rowSums 等只有 3 个参数)do_colsum 有 4,这你可以从 .Internal 调用 rowSums 中看到:

> rowSums
function (x, na.rm = FALSE, dims = 1L) 
{
    if (is.data.frame(x)) 
        x <- as.matrix(x)
    if (!is.array(x) || length(dn <- dim(x)) < 2L) 
        stop("'x' must be an array of at least two dimensions")
    if (dims < 1L || dims > length(dn) - 1L) 
        stop("invalid 'dims'")
    p <- prod(dn[-(1L:dims)])
    dn <- dn[1L:dims]
    z <- if (is.complex(x)) 
        .Internal(rowSums(Re(x), prod(dn), p, na.rm)) + (0+1i) * 
            .Internal(rowSums(Im(x), prod(dn), p, na.rm))
    else .Internal(rowSums(x, prod(dn), p, na.rm))
    if (length(dn) > 1L) {
        dim(z) <- dn
        dimnames(z) <- dimnames(x)[1L:dims]
    }
    else names(z) <- dimnames(x)[[1L]]
    z
}

关于c - 了解如何在 R 中处理 .Internal C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19663704/

相关文章:

r - 在 R 中将函数线程化到向量上的规则是什么?

r - tidyr 宽到长 : repeated measures and efficiency

r - 使用 R Markdown 进行交叉制表

java - 在java api上编写mongodb语法

c++ - 从现有指针 C++ 创建一个新对象

c - 按特定顺序对矩阵中的行重新排序

c - fscanf 返回错误的数字

java - MySQL Java 更新语法

c - 如何使用 Lua hooks 找出当前正在运行的函数的名称?

c++ - 如何以线程安全的方式在 openmp 中实现每个进程一次写入全局共享变量?