[英]Assigning value from struct to variable fails
Edit 3 describes the narrowed-down problem after debugging 编辑3描述了调试后缩小的范围
Edit 4 contains the solution - it's all about type difference between C and C# 编辑4包含解决方案-全部涉及C和C#之间的类型差异
Today I came across a curious problem. 今天我遇到一个奇怪的问题。 In CI have the following struct:
在CI中具有以下结构:
typedef struct s_z88i2
{
long Node;
long DOF;
long TypeFlag;
double CValue;
}s_z88i2;
Furthermore I have a function (this is a simplified version): 此外,我有一个功能(这是简化版):
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;
}
The assigned values are used nowhere - I'm aware of that. 分配的值无处使用-我知道。 When I reach
// Testplace 1
the following statement is executed: 当我到达
// 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
then is passed to a messagebox. 然后将
tmpstr
传递到消息框。 It shows - as one would expect - the values given in my struct I passed to the function in an nice and orderly way. 正如人们所期望的那样,它显示了我以良好且有序的方式传递给函数的结构体中给出的值。 Moving on through the function the values inside the struct get assigned to some variables.
通过该函数,将结构内部的值分配给某些变量。 On reaching
Testplace 2
the following is executed: 到达
Testplace 2
后,将执行以下操作:
sprintf(tmpstr,"RB, Node#: %li, DOF#: %li, Type#: %li, Value: %f",nkn, ifg, iflag1, wert);
Again, tmpstr
is passed to a messagebox. 同样,
tmpstr
传递到消息框。 However, this doesn't show what one would expect. 但是,这并没有显示出人们的期望。 The values for
Node
and Type
are still correct. Node
和Type
的值仍然正确。 For DOF
and Value
the displayed values are 0
which leads me to the conclusion that something is going terribly wrong during assigning the values. 对于
DOF
和Value
,显示的值为0
,这使我得出结论,在分配值期间出现了严重错误。 I somehow sometimes managed to get a way to long number for value whis was as incorrect as 0
. 我有时不知何故设法获得了一个长整数,因为值whis与
0
一样不正确。 But I have not been able to reproduce that mistake during my last tests. 但是在上一次测试中,我无法重现该错误。 Possible values for
inp
are eg {2,1,1,-451.387}
, so the first 1
and -451.387
are forgotten. 的可能值
inp
是例如{2,1,1,-451.387}
,所以第1
和-451.387
都忘了。
Does anyone know what I'm doing wrong or how to fix this? 有人知道我在做什么错或如何解决吗?
Many thanks in advance! 提前谢谢了!
Edit: 编辑:
Changed %i
to %li
but the result did not change. 将
%i
更改为%li
但结果未更改。 Thank to unwind! 谢谢放松!
I'm developing this dll with Dev-Cpp using MinGW (unfortunately) because I wasn't able to convince Visual Studio 2012 Pro to compile this properly. 我正在使用MinGW用Dev-Cpp开发此dll(不幸的是),因为我无法说服Visual Studio 2012 Pro正确地编译它。 Although the documentation of the original source says it is plain ANSI-C.
尽管原始资料的文档说它是普通的ANSI-C。 This bugs me a bit because I cannot debug this dll properly with Dev-Cpp.
这有点困扰我,因为我无法使用Dev-Cpp正确调试此dll。 Hence the messageboxes.
因此,消息框。
Edit 2: 编辑2:
As Neil Townsend suggested, I switched to passing a reference. 正如尼尔·汤森(Neil Townsend)所建议的那样,我转而通过一个参考。 But this also did not cure the problem.
但这也没有解决问题。 When I access the values in my struct directly everything is fine.
当我直接访问结构中的值时,一切都很好。 When I assign them to variables some get lost.
当我将它们分配给变量时,会迷路。
A short notice on how I'm calling the function. 关于我如何调用该函数的简短通知。 The dll is to be accessed from C#, so I'm meddeling with P/Invoke (as I get it).
该dll是从C#访问的,所以我正与P / Invoke混在一起(据我所知)。
[DllImport("z88rDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern int pass_i2(ref s_z88i2 inp, int total);
is my definition in C#. 是我在C#中的定义。 I have lots of other functions imported and they all work fine.
我还有很多其他导入的功能,它们都工作正常。 It is this function I encounter these Problems for the first time.
正是这个功能,我第一次遇到这些问题。 I call the function via:
我通过以下方式调用该函数:
s_z88i2 tmpi2 = FilesZ88.z88i2F.ConstraintsList[i];
int res = SimulationsCom.pass_i2(ref tmpi2, FilesZ88.z88i2F.ConstraintsList.Count);
First I set the struct, then I call the function. 首先,我设置结构,然后调用函数。
Why Oh Why has VS to be picky when it comes to compiling ANSI-C? 为什么?为什么在编译ANSI-C时VS会变得挑剔? It certainly would make things easier.
这肯定会使事情变得容易。
Edit 3: 编辑3:
I can narrow the problem down to sprintf
, I think. 我认为我可以将问题缩小到
sprintf
。 Having convinced VS to build my dll I was able to step through it. 说服VS构建我的dll后,我能够逐步解决它。 It appears that the values are assigned very nicely indeed to the variables they belong in. If, however I want to print these variables via
sprintf
they turn out rather empty ( 0
). 看来,这些值确实确实非常好地分配给了它们所属的变量。但是,如果我想通过
sprintf
打印这些变量,它们的结果将是空的( 0
)。 Curiously, that the value is always 0
and not something else. 奇怪的是,该值始终为
0
而不是其他值。 I'm still interested in why sprintf
behaves that way, but I consider my initial problem solved/panic defeated. 我仍然对
sprintf
为何采用这种方式感兴趣,但我认为最初的问题已解决/恐慌失败了。 So thanks everyone! 所以,谢谢大家!
Edit 4: 编辑4:
As supercat points out below, I had a rethink about type-compatibility between C and C#. 正如下面的超级猫指出的那样,我对C和C#之间的类型兼容性有了重新思考。 I was aware that an
int
in C# evaluates as a long
in C. But after double-checking I found that in C my variables are really FR_INT4
(which I kept out of the original question for reasons of clarity => bad idea). 我知道C#中的一个
int
在C中的计算结果很long
。但是在FR_INT4
检查之后,我发现在C中我的变量确实是FR_INT4
(出于清晰起见,我将其排除在原始问题之外,这是一个糟糕的主意)。 Internally FR_INT4
is defined as: #define FR_INT4 long long
, so as a super-long-long. 在内部将
FR_INT4
定义为: #define FR_INT4 long long
,因此是super-long-long。 A quick test showed that passing a long from C# gives the best compatibility. 快速测试表明,从C#中经过很长时间才能获得最佳兼容性。 So the
sprintf
-issue can maybe be simplified to the question: "What is the format-identifier of a long long?". 因此,可以将
sprintf
问题简化为一个问题:“ long long的格式标识符是什么?”。
It is %lli
which would is quite simple, actually. 实际上,这是
%lli
,非常简单。 So I can announce drumroll that my problem really is solved! 因此,我可以宣布鼓声真的解决了!
sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f\n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);
returns every value I want. 返回我想要的每个值。 Thank you very much everyone!
非常感谢大家!
Formatting a value of type long
with the format specifier %i
is not valid. 用格式说明符
%i
格式化long
类型的值无效。 You should use %li
. 您应该使用
%li
。
In C, it is a better approach to pass a reference or pointer to the struct rather than the struct. 在C语言中,将引用或指针传递给结构而不是结构是一种更好的方法。 So:
所以:
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;
}
You will need to correct the sprintf liness accordingly, inp.X
becomes inp->X
. 您需要相应地更正sprintf行,
inp.X
变为inp->X
To use this function either: 要使用此功能之一:
// 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);
or: 要么:
// 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);
This way pass_i2
will operate on the struct you send it, and any changes it makes will be there on return from pass_i2
. 这样,
pass_i2
将对您发送的结构进行操作,并且对它进行的任何更改都将在pass_i2
返回时pass_i2
。
To clarify this as answered: 为了澄清这个答案:
My struct actually is: 我的结构实际上是:
typedef struct s_z88i2
{
long long Node;
long long DOF;
long long TypeFlag;
double CValue;
}s_z88i2;
which requires long
to be passed from C# (and not int
as I previously thought). 这需要
long
才能从C#中传递(而不是我以前认为的int
)。 Through debugging I found out that the assignment of values behaves as it should, the problem was within sprintf
. 通过调试,我发现值的分配行为正常,问题出在
sprintf
之内。 If I use %lli
as format-identifier even this problem is solved. 如果我将
%lli
用作格式标识符,甚至可以解决此问题。
sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f\n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);
Is the statement I need to use. 是我需要使用的语句。 So thanks again everyone who contributed!
再次感谢所有贡献者!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.