2

編集3は、デバッグ後の絞り込まれた問題について説明しています

Edit 4には解決策が含まれています-それはすべてCとC#のタイプの違いに関するものです

今日、私は奇妙な問題に遭遇しました。CIには、次の構造体があります。

typedef struct s_z88i2
{
    long Node;
    long DOF;
    long TypeFlag;
    double CValue;

}s_z88i2;

さらに、私は関数を持っています(これは簡略化されたバージョンです):

DLLIMPORT int pass_i2(s_z88i2 inp, int total)
{
    long nkn=0,ifg=0,iflag1=0;
    double wert=0;
    int val;

    // Testplace 1
    nkn=inp.Node;
    ifg=inp.DOF;
    iflag1=inp.TypeFlag;
    wert=inp.CValue;
    // Testplace 2

    return 0;
}

割り当てられた値はどこにも使用されていません-私はそれを知っています。到達// Testplace 1すると、次のステートメントが実行されます。

char tmpstr[256];
sprintf(tmpstr,"RB, Node#: %li, DOF#: %li, Type#: %li, Value: %f", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);

tmpstrその後、メッセージボックスに渡されます。これは、予想どおり、関数に渡した構造で指定された値を適切かつ整然とした方法で示しています。関数を進めていくと、構造体内の値がいくつかの変数に割り当てられます。到達Testplace 2すると、以下が実行されます。

sprintf(tmpstr,"RB, Node#: %li, DOF#: %li, Type#: %li, Value: %f",nkn, ifg, iflag1, wert);

繰り返しtmpstrますが、メッセージボックスに渡されます。しかし、これは人が何を期待するかを示していません。Nodeとの値Typeはまだ正しいです。DOFValue表示された値は、0値の割り当て中に何かがひどく間違っているという結論に私を導きます。私はどういうわけか、値whisの長い数への道を得ることができたのと同じくらい間違っていまし0た。しかし、前回のテストではその間違いを再現することはできませんでした。の可能な値はinp、たとえば{2,1,1,-451.387}、なので、最初の1-451.387は忘れられます。

誰かが私が間違っていることやこれを修正する方法を知っていますか?

よろしくお願いします!

編集:

に変更%iされまし%liたが、結果は変更されませんでした。くつろいでくれてありがとう!

Visual Studio 2012 Proにこれを適切にコンパイルするように説得できなかったため、(残念ながら)MinGWを使用してDev-Cppでこのdllを開発しています。元のソースのドキュメントには、それはプレーンなANSI-Cであると記載されていますが。Dev-Cppでこのdllを適切にデバッグできないため、これは少しバグがあります。したがって、メッセージボックス。

編集2:

Neil Townsendが提案したように、私は参照を渡すことに切り替えました。しかし、これも問題を解決しませんでした。構造内の値に直接アクセスすると、すべて問題ありません。それらを変数に割り当てると、一部が失われます。

関数の呼び出し方法に関する簡単な通知。dllはC#からアクセスされるため、P / Invokeを使用しています(取得したとおり)。

[DllImport("z88rDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int pass_i2(ref s_z88i2 inp, int total);

C#での私の定義です。他にもたくさんの関数をインポートしていますが、それらはすべて正常に機能します。これらの問題に初めて遭遇したのはこの機能です。次の方法で関数を呼び出します。

s_z88i2 tmpi2 = FilesZ88.z88i2F.ConstraintsList[i];
int res = SimulationsCom.pass_i2(ref tmpi2, FilesZ88.z88i2F.ConstraintsList.Count);

最初に構造体を設定し、次に関数を呼び出します。

なぜああなぜANSI-Cのコンパイルに関してVSがうるさいのですか?それは確かに物事を容易にするでしょう。

編集3:

問題をに絞り込むことができるsprintfと思います。VSにdllをビルドするように説得したので、私はそれをステップスルーすることができました。値は、実際にそれらが属する変数に非常にうまく割り当てられているようです。ただし、これらの変数を介しsprintfて出力したい場合は、かなり空になります(0)。不思議なことに、その価値は常に他のものでは0ありません。なぜ そのように振る舞うのかはまだ興味がsprintfありますが、最初の問題は解決/パニックに負けたと思います。みんなありがとう!

編集4:

スーパーキャットが以下で指摘しているように、私はCとC#の間の型互換性について再考しました。intin C#はin Cとして評価されることを知っていlongました。しかし、ダブルチェックした後、Cでは変数が実際にFR_INT4あることがわかりました(明確にするために元の質問から除外しました=>悪い考えです)。内部的FR_INT4には次のように定義されます:#define FR_INT4 long long、のように、超ロングロング。簡単なテストでは、C#からlongを渡すと、最高の互換性が得られることが示されました。したがって、sprintf-issueは、「long longのフォーマット識別子は何ですか?」という質問に簡略化できます。

実際、これ%lliは非常に簡単です。だから、私の問題が本当に解決したことをドラムロールに発表することができます!

sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f\n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);

必要なすべての値を返します。みなさん、ありがとうございました!

4

3 に答える 3

1

タイプの値をlongフォーマット指定子でフォーマットする%iことは無効です。を使用する必要があります%li

于 2013-03-25T14:34:54.970 に答える
0

Cでは、構造体ではなく構造体への参照またはポインターを渡す方が適切なアプローチです。それで:

DLLIMPORT int pass_i2(s_z88i2 *inp, int total) {
    long nkn=0,ifg=0,iflag1=0;
    double wert=0;
    int val;

    // Testplace 1
    nkn=inp->Node;
    ifg=inp->DOF;
    iflag1=inp->TypeFlag;
    wert=inp->CValue;
    // Testplace 2

   return 0;
}

それに応じてsprintf行を修正する必要があり、にinp.Xなりinp->Xます。この関数を使用するには、次のいずれかを行います。

 // Option A - create it in a declaration, fill it, and send a pointer to that
 struct s_z88i2 thing;
 // fill out thing
 // eg. thing.Node = 2;
 pass_i2(&thing, TOTAL);

また:

 // Option B - create a pointer; create the memory for the struct, fill it, and send the pointer
 struct s_z88i2 *thing;
 thing = malloc(sizeof(struct s_z88i2));
 // fill out thing
 // eg thing->Node = 2;
 pass_i2(thing, TOTAL);

この方法pass_i2は、送信した構造体に対して機能し、それが行った変更は、から戻ったときにそこにありpass_i2ます。

于 2013-03-25T15:09:21.477 に答える
0

答えられたようにこれを明確にするために:

私の構造体は実際には次のとおりです。

typedef struct s_z88i2
{
    long long Node;
    long long DOF;
    long long TypeFlag;
    double CValue;
}s_z88i2;

これはlongC#から渡す必要があります(int以前考えていたようにではありません)。デバッグを通じて、値の割り当てが正常に動作することがわかりました。問題は内にありsprintfました。フォーマット識別子として使用すれば%lli、この問題も解決されます。

sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f\n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);

私が使用する必要があるステートメントです。貢献してくれた皆さん、ありがとうございました!

于 2013-03-27T07:45:01.820 に答える