2012-01-04 2 views
2

Как я могу вернуть массив struct из .Call в функцию в общей библиотеке C и впоследствии использовать этот массив в R?Как вернуть массив структур из .Call в C совместно используемую библиотеку в R

Например:

typedef struct{ 
    int thing1; 
    int thing2; 
    float thing3; 
    float thing4; 
    char thing5; 
    //... many more things of various simple types 
} MY_STRUCT; 

SEXP R_Calls_Me(SEXP args) { 

    // Do stuff with args... 

    // Create arrayOfMyStructs as what type?? 

    return arrayOfMyStructs; 
} 

Какой тип arrayOfMyStructs таким образом, что R может использовать его?

Это похоже на обычную вещь, которую хотелось бы сделать, но я не могу найти примеров этого в документации для написания расширений R.

ответ

3

Обычно вы создаете список (общий вектор) с компонентами, которые хотите вернуть. В вашем случае что-то вроде

SEXP res = PROTECT(allocVector(VECSXP, 5)); 
SET_VECTOR_ELT(res, 0, ScalarInteger(a.thing1)); 
SET_VECTOR_ELT(res, 1, ScalarInteger(a.thing2)); 
SET_VECTOR_ELT(res, 2, ScalarReal(a.thing3)); 
... 
UNPROTECT(1) 
return res; 

Также принято присваивать имена вектора, например .:

const char *names[5] = { "thing1", "thing2", "thing3", "thing4", "thing5" }; 
SEXP sNames = PROTECT(allocVector(STRSXP, 5)); 
for (int i = 0; i < 5; i++) SET_STRING_ELT(res, i, mkString(names[i])); 
setAttrib(res, R_NamesSymbol, sNames); 
UNPROTECT(1); 

Обратите внимание, что то, что вы описываете не массив, но структура. Массивы, как правило, намного проще передавать в виде векторов.

+0

В конечном счете, я хочу, чтобы возможность вернуть произвольное число этих структур, используя один вызов функции C. В вашем примере показано, как вернуть одну структуру. Могу ли я просто создать вектор векторов для этого? – cachance7

+0

Вы могли бы, если это удобно. В качестве альтернативы, если они одинаковы, вы можете использовать массивы (= векторы) - подумайте о кадре данных, где столбцы - это записи структуры, а строки - разные структуры. Вы бы заменили 'SET_VECTOR_ELT (res, 0, ScalarInteger (a.thing1))' что-то вроде 'SEXP t1 = allocVector (INTSXP, n); SET_VECTOR_ELT (res, 0, t1); int * t1i = INTEGER (t1); for (int i = 0; i

+0

Я думаю, что ваш второй подход имеет наибольшее значение для того, как я намерен использовать возвращаемые данные в R. Спасибо. – cachance7

2

Возможно, наиболее естественным способом является использование внешних указателей. Вы вернете указатель на R, а затем ваш код приложения будет управлять этим. В настоящее время существует несколько пакетов, например XML, h5r.

SEXP _h5R_make_ptr() { 
    h5_holder* holder = (h5_holder*) Calloc(1, h5_holder); 
    holder->id = 1; 
    holder->is_file = 0; 
    SEXP e_ptr = R_MakeExternalPtr(holder, R_NilValue, R_NilValue); 
    PROTECT(e_ptr); 
    R_RegisterCFinalizerEx(e_ptr, h5R_finalizer, TRUE); 
    UNPROTECT(1); 
    return e_ptr; 
} 
+0

За исключением того, что вы не можете использовать те, что указаны в R. Внешние указатели полезны только для непрозрачных структур, к которым R не имеет доступа (см. Вопрос, который вы не можете «впоследствии использовать в R»). –

Смежные вопросы