在 Rcpp 中,如何获取模板返回的字符串和数字

In Rcpp, how to get a strings and numbers returned with templates

这个问题的延续:

如何获得 return 字符串和数字的 Rcpp 模板,而不是某种类型的 "Vectors"?我正在尝试将其他人的 C 代码移植到 R 中,他们使用各种不同的数据类型(char、unsigned char、short、unsigned short、int、float、long int、long unsigned int、double - 不,真的,所有这些是实际的 header!),我需要将它们 "coerce" 转换为 R 中的字符串和数字。看到来自 "Ralf Stubner" 的评论,我修改了您的示例以生成显示问题的 MWE:

#include <RcppCommon.h>

typedef struct {
  char   firstname[128];
//  long unsigned int big_number;
} HEADER_INFO;

namespace Rcpp {
  template <>
    SEXP wrap(const HEADER_INFO& x);
}

#include <Rcpp.h>

namespace Rcpp {
  template <>
    SEXP wrap(const HEADER_INFO& x) {
      Rcpp::CharacterVector firstname(x.firstname, x.firstname + 128);
//      Rcpp::Integer big_number(x.big_number);
      return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = firstname
//                                           ,Rcpp::Named("big_number") = big_number
      ));
    };
}

//  [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
  HEADER_INFO header;
  strcpy( header.firstname, "Albert" );
//  header.big_number = 123456789012345;
  return header;
}

/*** R
getHeaderInfo()
*/

当你 运行 在 R:

> getHeaderInfo()
$firstname
  [1] "65"  "108" "98"  "101" "114" "116" "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [19] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [37] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [55] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [73] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [91] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
[109] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "127" "16" 
[127] "72"  "-29"

unsigned long 条目被注释掉了,因为我在 Rcpp 命名空间中找不到可以编译的数据类型。 "Rcpp::Integer" 和 "Rcpp::Double" 这样的类型真的不存在吗?如果我必须使用 IntegerVector,那么如何告诉模板我想将 R 中的结果仅作为整数而不是长度为 1 的向量来引用?

我看到 Rcpp::CharacterVector 的基于范围的构造函数令人困惑。这是必要的,因为使用了 char * 数组,即字符串数组。这里我们只有一个字符串(固定的最大长度)。 Rcpp 足够智能,可以将其单独转换为长度为 1 的 CharacterVector

大数的情况比较有意思。首先,不清楚什么是unsigned long int。它被定义为至少 32 位,在 32 位系统(和 64 位 Windows IIRC)上就是这种情况。在 64 位 Linux(和 MacOS?)上使用 64 位整数。现在 R 只知道 int 作为整数类型,它通常是 32 位宽但有符号,因此很小。然而,double 可以表示更大的整数 exactly,这是 R 本身在不同地方使用的技巧。所以在 32 位的系统上 unsigned long int 我们可以使用:

#include <RcppCommon.h>

typedef struct {
  char   firstname[128];
  long unsigned int big_number;
} HEADER_INFO;

namespace Rcpp {
  template <>
  SEXP wrap(const HEADER_INFO& x);
}

#include <Rcpp.h>

namespace Rcpp {
  template <>
  SEXP wrap(const HEADER_INFO& x) {
    static_assert(sizeof(long) <= 6, "long is to large");
    double big_number = x.big_number;
    return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = x.firstname,
                     Rcpp::Named("big_number") = big_number));
  };
}

//  [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
  HEADER_INFO header;
  strcpy( header.firstname, "Albert" );
  header.big_number = 4294967295;
  return header;
}

/*** R
getHeaderInfo()
 */

输出:

> getHeaderInfo()
$firstname
[1] "Albert"

$big_number
[1] 4294967295

两个列表元素实际上都是长度为 1 的向量。

在 64 位系统 unsigned long int 上,由于 static_assert,这将无法编译。在这样的系统上,您可以使用与 bit64 包相同的技巧:将 64 位整数的 位模式 复制到 64 位浮点数(即 double).这可以安全地传输到 R。但是,bit64 包将这些解释为 signed 整数。所以非常大的数字会溢出到负数。参见示例 integer64 and Rcpp compatibility and http://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/。我知道无符号数没有简单的解决方案。我认为您必须查明这些 unsigned long int 中的预期是否存在任何实际限制。