将值从struct分配给变量失败

时间:2013-03-25 14:29:27

标签: c# c struct assign

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

编辑4包含解决方案 - 它是关于C和C#之间的类型差异

今天我遇到了一个奇怪的问题。在C中我有以下结构:

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传递给消息框。它显示 - 正如人们所期望的那样 - 我的结构中给出的值我以一种良好有序的方式传递给函数。继续执行该函数,struct中的值将被赋予一些变量。达到Testplace 2后,执行以下操作:

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

再次,tmpstr被传递到消息框。但是,这并没有显示出人们的期望。 NodeType的值仍然正确。对于DOFValue,显示的值为0,这使我得出的结论是,在分配值时出现了严重错误。我不知何故有时设法找到一个方法来获得价值的长数字,这与0一样不正确。但是我在上次测试中无法重现那个错误。 inp的可能值为例如{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建议的那样,我转而传递参考资料。但这也无法解决问题。当我直接访问我的struct中的值时,一切都很好。当我将它们分配给变量时,会丢失一些。

关于我如何调用该函数的简短通知。该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#之间的类型兼容性。我知道C#中的int在C中评估为long但是经过仔细检查后我发现在C中我的变量实际上是FR_INT4(我保留了原来的FR_INT4出于清晰原因的问题=>坏主意)。内部#define FR_INT4 long long定义为:sprintf,因此定义为超长。快速测试表明,从C#传递一个长的时间可以获得最佳的兼容性。因此,%lli - 问题可以简化为以下问题:“long long的格式标识符是什么?”。

实际上它是sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f\n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue); 非常简单。所以我可以宣布 drumroll 我的问题真的解决了!

{{1}}

返回我想要的每个值。 非常感谢大家!

3 个答案:

答案 0 :(得分:1)

使用格式说明符long格式化%i类型的值无效。您应该使用%li

答案 1 :(得分: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 liness,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返回时,它所做的任何更改都会在那里进行。

答案 2 :(得分:0)

要澄清这一点:

我的结构实际上是:

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

需要{C}传递long(而不是我以前认为的int)。通过调试,我发现值的赋值表现得应该正常,问题在sprintf内。如果我使用%lli作为格式标识符,即使这个问题也解决了。

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

我需要使用的声明。再次感谢所有贡献的人!