何歳が一番楽しかった?

以下のようなプログラム(DLLとEXE)を書いたのですが、変数の値がおかしくなる(●参照)箇所があります。原因がお分かりになりましたら、ご回答をよろしくお願い致します。

●mkdll.cppの、sub1()の(※1)までは、input[]が正しい値で入っているが、(※2)で値がおかしくなる。(※1)から(※2)までで、input[]は参照するだけです。

---test.cpp(EXE)---

main(){
int input[10],output[10];
int err;
CDLL DLL;

err = DLL.func(input,output);

return(0);
}
---test.cpp End---

---mkdll.h(DLL)---

class __declspec(dllexport) CDLL{
public:
int func(int *input, int *output);
private:
int sub1(int *input, int *output);
int sub2(int in, int out);

};
---mkdll.h End---

---mkdll.cpp(DLL)---
#include "mkdll.h"

int CDLL::func(int *input, int*output){
int i;
int error;

error = sub1(input, output);
return(error);
}

int CDLL::sub1(int *input, int *outout){
int i;
int in1, in2, out1, out2;
int err;

//(※1)
for(i=0; i<5; i++){
err = 0;
in1 = input[i*2];
in2 = input[i*2+1];
//(※2)

err = sub2(in1, out1);
if(err != 0)
return(err);

}
}

---mkdll.cpp End---

A 回答 (5件)

ざっと見たところでは変数の値をおかしくするような要因はないようです。



回答No.1の指摘にある永続期間にしても、ローカル変数の値はスコープから外れるまで有効ですからDLL.func()の実行中にinput[]がなくなってしまうことはありませんし、DLLが実行されるのはDLLを呼び出しているプロセス内以外あり得ないのでローカル変数へのポインタが無効になってしまうこともありません。

質問の内容のコードはそのままでは実行できませんよね。これでは問題究明にも限度があります。いま手元にある問題が発生するコードから、問題とは関係ないと思われるコードをどんどん取り除いていって、実際に実行できて、なおかつ問題が発生するような最小限のコードを作成してみてください。

たいてはこの最小限のコードを作成する途上でうっかりミスの原因が見つかるものですが、どうしても見つからなければ、その「最小限のコード」を改めてここに掲示してみてください。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございました。そして、ソースを省略しすぎて大変申し訳ありませんでした。
結論から言いますと、おっしゃる通り、切り分け作業でコードをどんどん削除している中で、問題は解決しました。ただ、思いもよらない、というか、今でも何故それで解決したのか不明なのですが。

どのようなものかというと、EXEを作成するソースに、DLLからインポートするクラスのprivate変数を記述すると、問題が解決しました。インポートする側からはpublicだけ書いておけば良いと思っていたのですが…。

多分に、"たまたま"解決しただけの感もあるのですが(汗)、とりあえず動作するものを作るのが第一優先だったので、とても助かりました。ありがとうございました。

お礼日時:2005/06/23 01:09

No4 ngsvx さんが回答されているように、output[] が添え字の上限を越えてしまって、input[] の領域を破壊しているような気がします。



「…」で省略されているあたりの処理で、output[] に対して添え字を越えてしまって、for 文をグルグル回してませんか?
# たとえば、こんな感じとか。。。は、さすがにないですかねぇ。。。
------------------------------------------------

for ( i = 0; i < 10; i++ )
{
output[i*2] = out1;
output[i*2+1] = out2;
}

------------------------------------------------

関係ないですけど、out1 って設定せずに sub2() に渡してしまっているようですけど、これは大丈夫なのでしょうか?
ローカル変数ですし、不定値が入っていそうです。
# sub2() コール前に、実は out1 に何か値が設定されていて、その部分が
# 省略されているだけなら良いのですけど。。。


【参考】
(以下、私が良く使う手です。ご参考までに。。。)

私の場合、配列 (の先頭要素へのポインタ) を関数に渡す場合には、一緒に要素数も渡すようにしています。
たとえばこんな感じです。
------------------------------------------------

……
int func
(
int *input,
int input_num, /* input[] の要素数 */
int *output,
int output_num /* output[] の要素数 */
);
……
int sub1
(
int *input,
int input_num, /* input[] の要素数 */
int *output,
int output_num /* output[] の要素数 */
);
……

------------------------------------------------
# fgets() のイメージですね。

そして、関数側では配列 (の先頭要素へのポインタ) と一緒に渡された要素数を使って for 文でグルグル回すと。。。

あと、今回の原因には直接関係なさそうですが、入力用にポインタを渡す場合には const をつけてあげると、万が一のときに役立ちますよ。
間違って、そのポインタの参照先を書き換えようとした場合には、コンパイラがエラーを出してくれますから。。。

たとえば、こんな感じかな。

------------------------------------------------

……
int func
(
const int *input, /* 関数内で値を更新しないことを保障 */
int *output
);
……
int sub1
(
const int *input, /* 関数内で値を更新しないことを保障 */
int *output
);
……

------------------------------------------------
# strcpy() とかのイメージですね。

ま、面倒なことはコンパイルに任せてしまえ!という私の性格のなせるところですかねぇ。。。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございました。
そして、テクニックのご教授、ありがとうございます。是非、参考にさせていただきます。

>関係ないですけど、out1 って設定せずに sub2() に渡してしまっているようですけど、これは大丈夫なのでしょうか?
>ローカル変数ですし、不定値が入っていそうです。

省略しすぎで申し訳ありません。
sub2()の中で、out1には値が代入されるだけなので、設定していませんでした。まずいでしょうか…。

お礼日時:2005/06/23 01:21

>(※1)から(※2)までで、input[]は参照するだけです。



(※1)はループの外、(※2)はループの中にありますから、これだけのソースではわからないと思います。

(※2)以降のループ内で壊している可能性もあります。


想像ですが、配列outputの添え字上限を越えて書き込みをしたためinputの内容が破壊されているような気がします。
    • good
    • 1
この回答へのお礼

ご回答、ありがとうございました。
そして、ソースを省略しすぎで、申し訳ありませんでした。
ご指摘いただいた点について、outputをはじめとして配列の要素数以上に書き込んだり参照したりしていないかを確認してみました。
結論としては大丈夫でしたが、しっかり調査していなかったのは確かでしたので、再度新たな目で点検しなおすというきっかけを与えていただき、感謝いたします。

お礼日時:2005/06/23 01:15

うーん。

下の先生方と同じ見解ですが。。
一回中間モジュール等を削除して
コンパイルしてみてはいかがでしょうか?
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございました。
No.2 xcrOSgS2wY様へのご回答にも書きましたが、無関係な箇所を削除していくうちに(偶然ですが)問題が解決しました。
ありがとうございました。

お礼日時:2005/06/23 01:11

ローカル変数で宣言した変数を、プロセスの明確な永続期間指定せずにDLLで呼び出したって、何処のプロセスでDLLが実行されるかは、OS任せになるって事だけです。



プロセス(タスク)がスタックに積まれた時点でローカルの変数なんてどうなってるか分らないのでは?

しかも、このプログラムCの文法だからオブジェクトの永続性も無いです。
input[10],output[10];をオブジェクトの考え方でどこまで存続するか明確にすれば、値は保障されると思いますが。別解なら、宣言にstatic付けるとか。
    • good
    • 0
この回答へのお礼

早速のご回答、ありがとうございました。
関数の中で宣言したローカル変数の値は、その関数を抜
けたら保持されないというのはわかっていたのですが、
関数の中にいる時点でもそのようなことは起こり得るの
ですね。勉強になりました。

お礼日時:2005/06/22 23:19

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報