Ошибка при возврате значения из C в R с использованием .Call (возвращаются несовместимые типы указателей) - PullRequest
0 голосов
/ 01 февраля 2019

Я учусь использовать язык программирования C и, возможно, возникла проблема с возвратом несовместимых типов указателей.

У меня есть текстовый файл с двумя столбцами, который R считывается как data.frame.После прочтения этого я хочу выполнить .Call для функции в C, которая будет читать этот date.frame и будет возвращать значение для переменной в R, однако при попытке вернуть значение возникает ошибка segfault.Я не могу найти решение этой проблемы, кто-нибудь может мне помочь?

Текстовый файл структурирован в два столбца, как в примере ниже.

Q0045   YJL166W
Q0045   YDL085W
Q0045   YDR119W-A

Вот код C длячтение data.frame.

#include <Rinternals.h>
#include <Rdefines.h>
#include <R.h>
#include <stdlib.h>
#include <stdio.h>

char **test(SEXP lst){
  int i,elLength;
  int len = length(lst);
  SEXP col1, col2;
  char ***target = malloc(sizeof(char **) *len);
  col1 = VECTOR_ELT(lst, 0);
  col2 = VECTOR_ELT(lst, 1);
  elLength = length(col1);
  target[0] = malloc(sizeof(char *) * elLength);
  target[1] = malloc(sizeof(char *) * elLength);
  for (i=0; i<elLength; i++) {
    target[0][i] = CHAR(STRING_ELT(col1, i));
    target[1][i] = CHAR(STRING_ELT(col2, i));

  }

  return target;
} 

После этого я создаю файл .so с командной строкой в ​​терминале:

R CMD SHLIB test.c

И, наконец, код в R, который читает файл ивыполнить .Call.

dyn.load("/home/lab/test.so")
fileR = data.frame(read.table("file.txt", sep = "\t", stringsAsFactors = FALSE))
fileFromC = .Call("test", fileR)

После этого я получил ошибку, запущенную в R с терминала:

 *** caught segfault ***
address 0x310000c0, cause 'memory not mapped'

Если я только печатаю и возвращаю R_NilValue, ошибка не отображается.Но мне нужно вернуть процесс C в новую переменную.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Я смог сделать то, что мне было нужно, с помощью кода ниже.Спасибо всем, кто сотрудничал.

#include <Rinternals.h>
#include <Rdefines.h>
#include <R.h>
#include <stdlib.h>
#include <stdio.h>

char **stripList(SEXP lst){
  int i, j, elLength;
  int len = length(lst);
  char *rans;
  SEXP col1, col2;
  char ***target = (char *) R_alloc(len, sizeof(char **));

  col1 = VECTOR_ELT(lst, 0);
  col2 = VECTOR_ELT(lst, 1);

  elLength = length(col1);

  SEXP ans = PROTECT(Rf_allocMatrix(STRSXP,elLength, len));

  target[0] = malloc(sizeof(char *) * elLength);
  target[1] = malloc(sizeof(char *) * elLength);
  for (i=0; i<elLength; i++) {
    target[0][i] = CHAR(STRING_ELT(col1, i));
    target[1][i] = CHAR(STRING_ELT(col2, i));
  }

for (int i = 0; i < elLength; i++) for (int j = 0; j < len; j++) 
  SET_STRING_ELT(ans, i + j * elLength, Rf_mkChar(target[j][i]));

  UNPROTECT(1);

  return ans;
}
0 голосов
/ 01 февраля 2019

malloc() - неправильный способ обработки выделения памяти в расширениях R.

Пожалуйста, ознакомьтесь с документацией R, раздел 6.1. Распределение памяти

6.1.1 Распределение временного хранилища

Здесь R будет восстанавливать память в конце вызова .C, .Call или .External.Используйте

char *R_alloc(size_t n, int size)

, который выделяет n единиц размера байтов каждый.

т.е. вы используете этот распределитель для памяти, которую вы хотите return из вашего C API.

...