这个问题的继续: 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的向量?
答案 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 compatibility和http://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/。我知道没有简单的解决方案来解决无符号数字。我认为您必须找出这些unsigned long int
中预期的内容是否有实际限制。