编辑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
被传递到消息框。但是,这并没有显示出人们的期望。 Node
和Type
的值仍然正确。对于DOF
和Value
,显示的值为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}}
返回我想要的每个值。 非常感谢大家!
答案 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);
我需要使用的声明。再次感谢所有贡献的人!