2

编辑 3 描述了调试后缩小的问题

编辑 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. 但是在我上次的测试中,我无法重现这个错误。的可能值为inpeg {2,1,1,-451.387},因此第一个1-451.387被遗忘。

有谁知道我做错了什么或如何解决这个问题?

提前谢谢了!

编辑:

改成%i%li但结果没有改变。感谢放松!

我正在使用 MinGW(不幸的是)使用 Dev-Cpp 开发这个 dll,因为我无法说服 Visual Studio 2012 Pro 正确编译它。尽管原始来源的文档说它是普通的 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);

首先我设置结构,然后调用函数。

为什么哦 为什么VS在编译ANSI-C时要挑剔?它肯定会让事情变得更容易。

编辑3:

我认为,我可以将问题缩小到sprintf。在说服 VS 构建我的 dll 之后,我能够逐步完成它。看来,这些值确实很好地分配给了它们所属的变量。但是,如果我想通过sprintf它们打印这些变量,结果却是空的(0)。奇怪的是,价值始终是0而不是别的东西。我仍然对为什么会有 sprintf这种行为感兴趣,但我认为我最初的问题已经解决/恐慌被打败了。所以谢谢大家!

编辑4:

正如 supercat 在下面指出的那样,我重新考虑了 C 和 C# 之间的类型兼容性。我知道intC# 中的 a 评估为 C 中的 a 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

为了澄清这一点,回答:

我的结构实际上是:

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

这需要long从 C# 传递(而不是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 回答
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 回答