- PR -

VB.NETで文字列の構造体をバイト配列へコピーする方法

投稿者投稿内容
未記入
会議室デビュー日: 2006/08/10
投稿数: 6
投稿日時: 2006-08-17 10:38
返事が遅くなりました。元投稿者です。

>>本当に大丈夫ですか?「文字列」と、「文字配列」は違います。「文字列」には、必ず終端子
>>が入ります。サイズには、終端しも含まなければなりません。ただし、文字数には終端子は含
>>まれません。
>>しかし、「文字配列」は、そもそも終端子がありません。1文字しか入らない箱が並んでいる
>>だけですから。文字配列を文字列のように扱えるのは、配列が必ず連続したアドレスに割り振
>>られるからです。
●結果的にうまくいっているだけで、ダメなんでしょうか。
 終端子が含まれない文字列にしたいのですが、実現する方法は無いんでしょうか。

>>いま、UnmanagedType.ByValTStr, SizeConst:=3 と、文字列でサイズを3と指定していま
>>すが、このサイズには終端子が含まれなければなりません。3文字埋めてしまうと、終端子が
>>なくなって、文字列の終わりを判別できなくなるような気がします。
●これは
 UnmanagedType.ByValTStr, SizeConst:=4
 にする必要があるんでしょうか。
 やりたいのは、3バイトのエリアを確保したいのですが。
 最終的にByte型の配列をCのDLL(アンマネージド)に渡したいのですが
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-08-17 12:09
引用:

●結果的にうまくいっているだけで、ダメなんでしょうか。
 終端子が含まれない文字列にしたいのですが、実現する方法は無いんでしょうか。


C としては、基本的に文字列には終端文字が必須です。そうでなければメモリ上のどこまでが文字列なのか判断できませんから。

引用:

 やりたいのは、3バイトのエリアを確保したいのですが。
 最終的にByte型の配列をCのDLL(アンマネージド)に渡したいのですが


結局のところ、アンマネージド関数が何を要求しているかによります。
文字列を要求しているのなら終端文字は必須ですし、ただのバイト配列を要求しているのなら不要です。
その判断は関数の仕様を知らない私たちにはできませんので、スレ主さんが考えてください。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-08-17 23:30
引用:

未記入さんの書き込み(2006-08-17 10:38)より:

>>本当に大丈夫ですか?「文字列」と、「文字配列」は違います。「文字列」には、必ず終端子
>>が入ります。サイズには、終端しも含まなければなりません。ただし、文字数には終端子は含
>>まれません。
>>しかし、「文字配列」は、そもそも終端子がありません。1文字しか入らない箱が並んでいる
>>だけですから。文字配列を文字列のように扱えるのは、配列が必ず連続したアドレスに割り振
>>られるからです。
●結果的にうまくいっているだけで、ダメなんでしょうか。
 終端子が含まれない文字列にしたいのですが、実現する方法は無いんでしょうか。


 「結果的に」であったとしても、「うまくいっている」と言い切れますか?「うまくいっているように見える」ではないと、自信を持って言い切れますか?
 私は、そう指摘しているわけですが、それを覆せる「理由」がありますか?
# こういうところに「基礎知識」が必要なわけです

 終端子が含まれない文字列というのは、存在しません(DBMS ではあるのかもしれませんが)。いや Delphi は終端子が無くて、代わりに文字数があるんだっけ?どちらにしても、「文字列」は不定長なので、文字列の終わりを何らかの形で指定してやらなければなりません。人間にとって「ここで終わっている」と思えるのは、意識していない終端子があるからです。コンピュータに対しては、明示してやらなければなりません。


引用:

>>いま、UnmanagedType.ByValTStr, SizeConst:=3 と、文字列でサイズを3と指定していま
>>すが、このサイズには終端子が含まれなければなりません。3文字埋めてしまうと、終端子が
>>なくなって、文字列の終わりを判別できなくなるような気がします。
●これは
 UnmanagedType.ByValTStr, SizeConst:=4
 にする必要があるんでしょうか。
 やりたいのは、3バイトのエリアを確保したいのですが。
 最終的にByte型の配列をCのDLL(アンマネージド)に渡したいのですが


 使う側が、どの様に使うかの問題です。先にも書いたように、「文字列」であれば、終端子が必要です。しかし、「文字配列」で、配列数を別に管理しているのであれば、終端子を含む必要はありません。
 受け側の C 言語で、次のように定義されているとします。
コード:
typedef struct _BUF {
	char data1[3];
	char data2[3];
} BUF;


この構造体を、次の (A) のように使うのであれば、問題ありません。しかし、 (B) のように扱うのなら、問題です。
示されているコードだけでは、C 言語でどの様に使うのかがわかりません。C 言語側が (A) のように使っているなら、問題はないでしょう。しかし、(B) のように使っているなら、うまくいっているように見えているだけです。
コード:
(A)
	BUF *buffer = 受け取るための関数();
	char str[4];
	memset(str, NULL, sizeof(str));
	memcpy(str, buffer->data1, 3);
	printf("受け取った値 [%s]", str);

(B)
	BUF *buffer = 受け取るための関数();
	printf("受け取った値 [%s]", buffer->data1);



蛇足:
 私は UNIX 出身なので、alignment 境界というのを意識するため、char [3] という確保はしないんですね。必ず、int のバイト数(もしくはポインタのバイト数)の整数倍、確保します。
 int が 4 バイトとして、アライメント調整をする場合、struct _BUF は、6 バイトに見えますが、ファイルに書き出すと 8 バイトになるんですね。これは、data2 の後に、アライメント調整のために 2 バイト確保されてしまうからです。
コード:
struct _example {
	char ex1[3];
	int iex1;
	char ex2[3];
};


と定義すると、この構造体は 3 + 4 + 3 = 10 ではなく、3 + (1) + 4 + 3 + (1) = 12 バイトの大きさを持つことになります。
 BUF の定義がこうだとすると、(B) のように使ったとしても、アライメント調整のためにとられた不可視の 1 バイトによって、(これが NULL に初期化されていれば)うまくいっているように見えます。
 ところが、iex1 の定義を上にずらすと、4 + 3 + 3 + (2) となって、ex1 の文字列と ex2 の文字列が連結してしまうという現象が発生します。
コード:
struct _example {
	int iex1;
	char ex1[3];
	char ex2[3];
};

struct _example ex;
memcpy(ex.ex1, "abc", 3);
memcpy(ex.ex2, "def", 3);
printf("%s", ex.ex1); → "abcdef"
printf("%s", ex.ex2); → "def"



 もっとも、古い UNIX の話なので、当てはまるかどうかはわかりません。UNIX でも、コンパイル オプションで、アライメント調整をしないようにすることも出来たし。
(double があると 8 バイトだったような気もする。。。)

スキルアップ/キャリアアップ(JOB@IT)