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

时间:2018-07-03 16:25:48

标签: rcpp

这个问题的继续: In Rcpp, how to get a user-defined structure from C into R

如何获取Rcpp模板以返回字符串和数字,而不是某种类型的“向量”?我试图将其他人的C代码移植到R中,并且它们使用各种不同的数据类型(char,unsigned char,short,unsigned short,int,float,long int,long unsigned int,double-不,真的,所有这些都在实际的标头中!)我需要“强制”为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"

未签名的长条目已被注释掉,因为我在Rcpp命名空间中找不到可以编译的数据类型。是否确实存在诸如“ Rcpp :: Integer”和“ Rcpp :: Double”之类的类型?如果我必须使用IntegerVector,那么如何告诉模板我要引用R中的结果只是一个整数而不是长度为1的向量?

1 个答案:

答案 0 :(得分:1)

我看到Rcpp::CharacterVector的基于范围的构造函数令人困惑。这是必需的,因为使用了char *数组,即字符串数组。在这里,我们只有一个字符串(最大长度固定)。 Rcpp非常聪明,可以将其本身转换为长度为CharacterVector的所有内容。

大数字的情况更有趣。首先,不清楚unsigned long int是什么。它被定义为至少32位,在32位系统(和64位Windows IIRC)上就是这种情况。在64位Linux(和MacOS?)上,使用64位整数。现在,R仅知道int为整数类型,该类型通常为32位宽,但有符号且因此较小。但是,double可以完全表示更大的整数,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 compatibilityhttp://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/。我知道没有简单的解决方案来解决无符号数字。我认为您必须找出这些unsigned long int中预期的内容是否有实际限制。