从结构体给变量赋值失败
本文关键字:赋值 失败 变量 结构体 | 更新日期: 2023-09-27 18:05:36
编辑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
传递给消息框。正如人们所期望的那样,它显示了我以一种良好而有序的方式传递给函数的结构中给定的值。在函数中,结构体中的值被赋值给一些变量。当到达Testplace 2
时执行如下命令:
sprintf(tmpstr,"RB, Node#: %li, DOF#: %li, Type#: %li, Value: %f",nkn, ifg, iflag1, wert);
同样,将tmpstr
传递给消息框。然而,这并没有显示出人们所期望的。"Node
"answers"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建议的那样,我转而传递一个引用。但这也没有解决问题。当我直接访问我的结构中的值时,一切都很好。当我把它们赋值给变量时,有些会丢失。
关于如何调用函数的简短通知。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
,因此作为一个超长长。一个快速的测试表明,从c#传递一个long可以获得最好的兼容性。因此,sprintf
-问题可以简化为这样一个问题:"long - long的格式标识符是什么?"
它是%lli
,这将是相当简单的,实际上。所以我可以宣布鼓声我的问题真的解决了!
sprintf(tmpstr,"RB, Node#: %lli, DOF#: %lli, Typ#: %lli, Wert: %f'n", inp.Node, inp.DOF, inp.TypeFlag, inp.CValue);
返回我想要的所有值。非常感谢大家!
不能用格式说明符%i
格式化类型为long
的值。您应该使用%li
.
在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
返回时存在。
澄清这个问题:
我的结构实际上是:
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);
是我需要使用的语句。所以再次感谢所有贡献的人!