将字符缓冲区移植到 Rcpp 中

Porting character buffers into Rcpp

我正在尝试 运行 使用 Rcpp 在 R 中编写 C 代码,但不确定如何转换用于保存文件数据的缓冲区。在下面的第三行代码中,我分配了一个 unsigned char 缓冲区,但我的问题是我不知道要使用哪种 Rcpp 数据类型。将数据读入缓冲区后,我想出了如何使用 Rcpp::NumericMatrix 来保存最终结果,而不是字符缓冲区。我已经看到 Dirk Eddelbuettel 对类似问题的几个回应,他建议用 Rcpp 初始化命令替换所有 'malloc' 调用。我尝试使用 Rcpp::CharacterVector,但最后循环中存在类型不匹配:Rcpp::CharacterVector 无法读取为 unsigned long long int。某些 C 编译器的代码 运行s,但对其他编译器会抛出 'memory corruption' 错误,所以我更愿意按照 Dirk 建议的方式做事(使用 Rcpp 数据类型),这样代码将 运行 与特定编译器无关。

    FILE *fp = fopen( filename, "r" );
    fseek( fp, index_data_offset, SEEK_SET );
    unsigned char* buf = (unsigned char *)malloc( 3 * number_of_index_entries * sizeof(unsigned long long int) );
    fread( buf, sizeof("unsigned long long int"), (long)(3 * number_of_index_entries), fp );
    fclose( fp );

    // Convert "buf" into a 3-column matrix.
    unsigned long long int l;
    Rcpp::NumericMatrix ToC(3, number_of_index_entries);
    for (int col=0; col<number_of_index_entries; col++ ) {
        l = 0;
        int offset = (col*3 + 0)*sizeof(unsigned long long int);
        for (int i = 0; i < 8; ++i) {
            l = l | ((unsigned long long int)buf[i+offset] << (8 * i));
        }
        ToC(0,col) = l;

        l = 0;
        offset = (col*3 + 1)*sizeof(unsigned long long int);
        for (int i = 0; i < 8; ++i) {
            l = l | ((unsigned long long int)buf[i+offset] << (8 * i));
        }
        ToC(1,col) = l;

        l = 0;
        offset = (col*3 + 2)*sizeof(unsigned long long int);
        for (int i = 0; i < 8; ++i) {
            l = l | ((unsigned long long int)buf[i+offset] << (8 * i));
        }
        ToC(2,col) = l;
    }
    return( ToC );

C 和 C++ 可以很可爱。如果您知道自己在做什么,那么您就可以通过 非常 直达底层硬件 更高级别的抽象来进行有效推理。

我建议简化和减少问题。从一个简单且已知的案例开始,例如 double 的 STL 向量。让我们来电是x。用 10 个或一百个元素填充它,然后打开一个 FILE 并从

写入一个 blob
x.data(),  x.size() * sizeof(double)

关闭文件。通过首先分配一个相同大小的 NumericVector v 将其读入 Rcpp,然后读回字节,然后将 memcpy 调用到 &(v[0]).

应该是同一个向量

然后你可以泛化到不同的类型。 因为向量保证是连续的内存你可以直接使用这个序列化技巧。

您可以使用字符缓冲区对此进行变体,或者 void*,或者... None 重要的 只要您注意不要不匹配 不要将 int 有效负载分配给 double 等等。

现在,推荐吗?不,除非你追求性能并且足够了解你在做什么,在这种情况下这是合理的。否则依赖 fantastic 现有包,如 fst or qs 为你做。

希望对您的问题有所帮助。我不完全是 你在问什么。如果没有,也许你会澄清(并可能缩短/重点)它。

类型转换成功了:

    Rcpp::NumericVector NumVecBuf( 3 * number_of_index_entries * sizeof(unsigned long long int) );
    unsigned char* buf = (unsigned char*) &(NumVecBuf[0]);

Dirk 关于 "contiguous memory" 的声明表明这可行,因此我继续将他的评论标记为答案。谢谢,德克!并且,感谢您开发和维护 Rcpp!