Предаване на аргумент на указател в MATLAB към C-DLL функция foo(char**)

Пиша C-DLL, която да бъде извикана от MATLAB. Възможно ли е да се извика функция с параметър const char **? напр.

void myGetVersion( const char ** );

C кодът ще бъде:

const char *version=0;
myGetVersion( &version );

Какъв би бил съответният MATLAB-код (ако изобщо е възможно)?

Благодаря ти много!

P.S.: Мисля, че това е страницата за помощ, но можех не намирам моя случай :-(


person Valentin Heinitz    schedule 16.09.2011    source източник


Отговори (3)


Отговорът е да се изгради указател към c-низ с помощта на LIBPOINTER функционира като @JonasHeidelberg предложено. Нека разширя неговото решение с работещ пример.

Първо нека изградим проста DLL:

версия.h

#ifndef VERSION_H
#define VERSION_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
#   ifdef BUILDING_DLL
#       define DLL_IMPORT_EXPORT __declspec(dllexport)
#   else
#       define DLL_IMPORT_EXPORT __declspec(dllimport)
#   endif
#else
#   define DLL_IMPORT_EXPORT
#endif

DLL_IMPORT_EXPORT void myGetVersion(char**str);

#ifdef __cplusplus
}
#endif

#endif

версия.c

#include "version.h"
#include <string.h>

DLL_IMPORT_EXPORT void myGetVersion(char **str)
{
    *str = strdup("1.0.0");
}

Можете да използвате предпочитания от вас компилатор за изграждане на DLL библиотеката (Visual Studio, MinGW GCC, ..). Използвам MinGW, за да компилирам горното, ето make-файла, който използвам:

Makefile

CC = gcc

all: main

libversion.dll: version.c
    $(CC) -DBUILDING_DLL version.c -I. -shared -o libversion.dll

main: libversion.dll main.c
    $(CC) main.c -o main -L. -lversion

clean:
    rm -rf *.o *.dll *.exe

Преди да преминем към MATLAB, нека тестваме библиотеката с C програма:

main.c

#include <stdio.h>
#include <stdlib.h>
#include "version.h"

int main()
{
    char *str = NULL;
    myGetVersion(&str);
    printf("%s\n", str);
    free(str);

    return 0;
}

Сега, когато всичко работи, ето как да използвате тази библиотека от MATLAB:

testDLL.m

%# load DLL and check exported functions
loadlibrary libversion.dll version.h
assert( libisloaded('libversion') )
libfunctions libversion -full

%# pass c-string by reference
pstr = libpointer('stringPtrPtr',{''}); %# we use a cellarray of strings
get(pstr)
calllib('libversion','myGetVersion',pstr)
dllVersion = pstr.Value{1}

%# unload DLL
unloadlibrary libversion

Резултатът с върнатия низ:

Functions in library libversion:
stringPtrPtr myGetVersion(stringPtrPtr)

       Value: {''}
    DataType: 'stringPtrPtr'

dllVersion =
1.0.0
person Amro    schedule 16.09.2011
comment
Това е, което наричам пълен отговор :-) - person Jonas Heidelberg; 16.09.2011
comment
Благодаря ти много! Това беше много повече, отколкото смеех да очаквам :-) - person Valentin Heinitz; 18.09.2011

Разглеждате Работа с указатели, раздел Предаване на масив от низове в документацията на MATLAB (свързана от страницата за помощ, която сте свързали във вашия въпрос), изглежда, че трябва да конструирате libpointer обект в MATLAB, нещо като

version = libpointer('stringPtrPtr',{''}); %# corrected according to Amro's comment
calllib('yourCdll', 'myGetVersion', version)

(В момента нямам DLL, с който да тествам това, и не съм много твърд в C указателите, така че няма гаранция... надявам се, че това е стъпка в правилната посока)

person Jonas Heidelberg    schedule 16.09.2011
comment
+1, но трябва да използвате клетъчен масив от низ, когато инициализирате stringPtrPtr - person Amro; 16.09.2011

Не можах да накарам решението на @Amro да работи (стара версия на MATLAB?). И така, трябваше да направя нещо малко по-креативно:

pstr = libpointer('voidPtr');
ret = calllib('libversion', 'myGetVersion', pstr);
% establish the length
n = 0;
while n==0 || pstr.Value(n) ~= 0
    n=n+1;
    pstr.setdatatype('uint8Ptr', 1, n);
end
% truncate to exclude the NULL character
pstr.setdatatype('uint8Ptr', 1, n-1);
% convert to string
display(char(pstr.Value))
person Compholio    schedule 07.08.2017