ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

ポインター引数の操作

C 関数内でのポインター引数

外部ライブラリの多くの関数は、参照によって引数を受け渡します。参照で渡すときは、値への "ポインター" を渡します。関数シグネチャでは、これらは Ptr および PtrPtr で終わる名前の引数です。MATLAB® では参照による受け渡しをサポートしていませんが、C ポインターと互換性のある "lib.pointer オブジェクト" と呼ばれる MATLAB 引数を作成できます。このオブジェクトは、MATLAB lib.pointer クラスのインスタンスです。

多くの場合、関数のシグネチャが引数をポインターとして宣言している場合でも、MATLAB 変数をそのまま渡すことができます (値による引数の受け渡し)。ただし、lib.pointer を渡すほうが便利な場合もあります。

  • 入力引数のデータを変更する場合。

  • 大量のデータを渡す際に、MATLAB がデータをコピーするタイミングを制御する場合。

  • ライブラリではポインターが一定期間保存されて使用されるため、lib.pointer オブジェクトの寿命を MATLAB 関数で制御する場合。

プリミティブ型へのポインターの作成

この例は、ポインターの作成および受け渡しの方法および出力の解釈方法を示しています。shrlibsample ライブラリの関数 multDoubleRef を使用して入力を 5 で乗算します。入力は double へのポインターで、double へのポインターを返します。

 C 関数 multDoubleRef

入力データ x を指す lib.pointer オブジェクト xp を作成します。

x = 15;
xp = libpointer('doublePtr',x);

xp のコンテンツを確認します。

get(xp)
       Value: 15
    DataType: 'doublePtr'

ここで、関数を呼び出し、結果を調べます。

calllib('shrlibsample','multDoubleRef',xp)
xp.Value
ans =
   75

オブジェクト xp は、"ハンドル オブジェクト" です。このハンドルのすべてのコピーは、基となる同じオブジェクトを参照し、1 つのハンドル オブジェクトで実行される演算はそのオブジェクトのすべてのコピーに影響します。ただし、オブジェクト xp は C 言語ポインターではありません。このオブジェクトは x を指しますが、x のアドレスは含みません。関数は、xpValue プロパティを変更しますが、基となるオブジェクト x の値は変更しません。x の元の値はそのままです。以下を入力します。

x
x =
     15

関数の戻り値の読み取り

前の例では、MATLAB から呼び出された関数の結果は、変更された入力ポインターを検査することで取得できました。しかし、この関数は出力引数でも有用なデータを返す可能性があります。

multDoubleRef の MATLAB シグネチャを確認するには、以下を入力します。

libfunctions shrlibsample -full

 multDoubleRef の関数シグネチャ

関数は 2 つの出力、すなわち lib.pointer オブジェクトと入力引数の Value プロパティを返します。

例を再び実行します。

x = 15;
xp = libpointer('doublePtr',x);

出力値を確認します。

[xobj,xval] = calllib('shrlibsample','multDoubleRef',xp)
xobj =
   lib.pointer
xval =
    75

入力引数 xp と同様に、xobjlib.pointer オブジェクトです。この出力は検査可能ですが、この関数では型とサイズのプロパティが未定義であるため、まずこれを初期化する必要があります。lib.pointer クラスの setdatatype メソッドを使用して、データ型を doublePtr に、サイズを 11 列に設定します。初期化後、以下を入力して出力を検査します。

setdatatype(xobj,'doublePtr',1,1)
get(xobj)
ans = 
       Value: 75
    DataType: 'doublePtr'

multDoubleRef の 2 番目の出力 xval は、入力 xpValue プロパティのコピーです。

既存の lib.pointer オブジェクトからのオフセットによるポインターの作成

plus 演算子 (+) を使用して、既存のポインターからスカラー数値分オフセットされた新しいポインターが作成できます。たとえば、ベクトル x を指す lib.pointer を作成するとします。

x = 1:10;
xp = libpointer('doublePtr',x);
xp.Value
ans =
     1     2     3     4     5     6     7     8     9    10

plus 演算子を使用して、xp からのオフセット位置を指す新しい lib.pointer を作成します。

xp2 = xp+4;
xp2.Value
ans =
     5     6     7     8     9    10

    メモ:   新しいポインター (この例では xp2) は、元のポインター xp が存在する間のみ有効です。

構造体へのポインターの作成

関数に構造体へのポインターである入力引数が含まれる場合、その構造体自体を渡すことも、構造体へのポインターを渡すこともできます。構造体へのポインターは、プリミティブ型へのポインターと同様にして作成します。

shrlibsample ライブラリ内の関数 addStructByRef は、c_struct 型の構造体へのポインターを取ります。出力引数は、構造体内のすべてのフィールドの合計になります。この関数は、入力構造体のフィールドも変更します。

 C 関数 addStructByRef

構造体自体の受け渡し

関数 addStructByRef への入力は、構造体へのポインターですが、構造体自体を渡し、MATLAB にこれをポインターに変換させることもできます。

以下の例では、構造体 sm を作成し、addStructByRef を呼び出します。

sm.p1 = 476;
sm.p2 = -299;
sm.p3 = 1000;
x = calllib('shrlibsample','addStructByRef',sm)
x =
        1177

ただし、sm はポインターではないため、MATLAB ではその内容は変更されません。以下を入力します。

sm
sm = 
    p1: 476
    p2: -299
    p3: 1000

構造体ポインターの受け渡し

以下の例では、構造体にポインターを渡します。まず、次のように lib.pointer オブジェクトを作成します。

sp = libpointer('c_struct',sm);
sp.Value
ans = 
    p1: 476
    p2: -299
    p3: 1000

lib.pointer である sp の値は、構造体 sm と同じです。

関数に lib.pointer を渡します。

if not(libisloaded('shrlibsample'))
    addpath(fullfile(matlabroot,'extern','examples','shrlib'))
    loadlibrary('shrlibsample')
end
calllib('shrlibsample','addStructByRef',sp)
ans =
        1177

ここでは、関数によって構造体フィールドが変更されます。以下を入力します。

sp.Value
ans = 
    p1: 5.5000
    p2: 1234
    p3: 12345678

MATLAB は更新された値を表示します。

配列の最初の要素へのポインターの受け渡し

関数が、データ配列の最初の要素へのポインターである入力引数を定義する場合、MATLAB では、MATLAB ベクトルまたは行列内のデータの最初の要素への正しい型のポインターである引数が自動的に渡されます。

以下の "疑似コード" はこの実行方法を示しています。ライブラリ myLib に関数 mySum があるとします。C 関数のシグネチャは次のとおりです。

戻り値の型名前引数
intmySum(int size,
short* data)

C 変数 data は、short 型の配列です。これに相当する MATLAB の型は、int16 です。この関数には次の MATLAB 変数のどれでも渡すことができます。

Data = 1:100;
shortData = int16(Data); % equivalent to C short type
lp = libpointer('int16Ptr',Data); % libpointer object

以下の "疑似コード" ステートメントはいずれも同じ意味です。

summed_data = calllib('myLib','mySum',100,Data)
summed_data = calllib('myLib','mySum',100,shortData)
summed_data = calllib('myLib','mySum',100,lp)

data ベクトルの長さは、指定された size と同じでなければなりません。以下に例を示します。

% sum last 50 elements
summed_data = calllib('myLib','mySum',50,Data(51:100)) 

文字列をボイド ポインターに含める

C は、文字を 8 ビットの整数として表現します。入力引数として MATLAB 文字列を使用するには、文字列を正しい型に変換し、voidPtr を作成しなければなりません。これを行うには、次のように関数 libpointer を使用します。

str = 'string variable';
vp = libpointer('voidPtr',[int8(str) 0]);

構文 [int8(str) 0] は、C 関数で必要な null 終端文字列を作成します。文字列を読み取り、ポインターの型を確認するには、以下を入力します。

char(vp.Value)
vp.DataType
ans = 
string variable
ans = 
voidPtr

外部関数プロトタイプが引数をポインターとして定義している場合、MATLAB では、値によって渡された引数が参照によって渡された引数に自動的に変換されるため、次の構文を使用して、入力引数として文字列に voidPtr を取る関数を呼び出すことができます。

func_name([int8(str) 0])

MATLAB は引数を値からポインターに変換しますが、それは正しい型でなければなりません。

文字列の配列の受け渡し

shrlibsample ライブラリの関数 getListOfStrings は、文字列の配列へのポインターと見なすことのできる char ** を返します。

 getListOfStrings の関数シグネチャ

 C 関数 getListOfStrings

この配列を読み取るには、以下を入力します。

if not(libisloaded('shrlibsample'))
    addpath(fullfile(matlabroot,'extern','examples','shrlib'))
    loadlibrary('shrlibsample')
end
ptr = calllib('shrlibsample','getListOfStrings')

MATLAB は、stringPtrPtr 型の lib.pointer オブジェクト ptr を作成します。このオブジェクトは最初の文字列を指します。文字列を表示するには、Value プロパティを使用します。

ptr.Value

その他の文字列を表示するには、ポインターをインクリメントする必要があります。たとえば、以下を入力します。

for index = 0:3
  tempPtr = ptr + index;
  tempPtr.Value
end 
ans = 
    'String 1'
ans = 
    'String Two'
ans = 
    {''}
ans = 
    'Last string'

他の例については、配列による反復を参照してください。

外部ライブラリ用メモリの割り当て

通常、MATLAB は、ライブラリ関数に変数が渡されるたびに、有効なメモリ アドレスを渡します。ライブラリがポインターを格納し、一定期間バッファーにアクセスする場合は、lib.pointer オブジェクトを使用する必要があります。この場合、MATLAB がバッファーの寿命を制御できることを確認し、データのコピーが作成されないようにしなければなりません。次の疑似コードは非同期データ収集の例であり、この状況で lib.pointer を使用する方法を示しています。

外部ライブラリ myLib に次の関数があるとします。

AcquireData(int points,short *buffer)
IsAquisitionDone(void)

ここで、buffer は次のように宣言されます。

short buffer[99]

まず、99 の points からなる配列を指す lib.pointer を作成します。

BufferSize = 99;
pBuffer = libpointer('int16Ptr',zeros(BufferSize,1));

次に、データの取得を開始し、それが完了するまでループで待機します。

calllib('myLib','AcquireData,BufferSize,pbuffer)
while (~calllib('myLib','IsAcquisitionDone')
  pause(0.1)
end

次のステートメントは、バッファー内のデータを読み取ります。

result = pBuffer.Value;

ライブラリがバッファーの使用を終了した後、MATLAB 変数をクリアします。

clear pBuffer

マルチレベル ポインター

"マルチレベル ポインター" とは、複数レベルの参照のある引数のことです。MATLAB のマルチレベル ポインター型は、接尾辞 PtrPtr を使用します。たとえば、C 引数 double ** には doublePtrPtr を使用します。

マルチレベル ポインター引数をとる関数を呼び出す場合、lib.pointer オブジェクトを使用し、MATLAB でマルチレベル ポインターに変換します。たとえば、shrlibsample ライブラリの関数 allocateStructc_structPtrPtr 引数を取ります。

 allocateStruct の関数シグネチャ

 C 関数 allocateStruct

c_structPtr 型の lib.pointer オブジェクトを作成し、関数に渡します。

if not(libisloaded('shrlibsample'))
  addpath(fullfile(matlabroot,'extern','examples','shrlib'))
  loadlibrary('shrlibsample')
end
sp = libpointer('c_structPtr');
calllib('shrlibsample','allocateStruct',sp)
get(sp)
ans = 
       Value: [1x1 struct]
    DataType: 'c_structPtr'

以下を入力します。

sp.Value
ans = 
    p1: 12.4000
    p2: 222
    p3: 333333

関数 allocateStruct を使用する場合、次のコマンドを使用してメモリを解放しなければなりません。

calllib('shrlibsample','deallocateStruct',sp)

文字列の配列の返却

文字列の配列を読み取る関数 acquireString を含むライブラリ myLib があるとします。関数シグネチャは次のようになります。

戻り値の型名前引数
char**acquireString(void)

char** acquireString(void)

以下の "疑似コード" は、文字列へのポインターの配列である戻り値を操作する方法を示しています。

ptr = calllib(myLib,'acquireString')

MATLAB は、stringPtrPtr 型の lib.pointer オブジェクト ptr を作成します。このオブジェクトは最初の文字列を指します。その他の文字列を表示するには、ポインターをインクリメントする必要があります。たとえば、最初の 3 つの文字列を表示するには、以下を入力します。

for index = 0:2
  tempPtr = ptr + index;
  tempPtr.Value
end 
ans = 
    'str1'
ans = 
    'str2'
ans = 
    'str3'
この情報は役に立ちましたか?