从结构体给变量赋值失败

本文关键字:赋值 失败 变量 结构体 | 更新日期: 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"的值仍然正确。对于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建议的那样,我转而传递一个引用。但这也没有解决问题。当我直接访问我的结构中的值时,一切都很好。当我把它们赋值给变量时,有些会丢失。

关于如何调用函数的简短通知。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);

是我需要使用的语句。所以再次感谢所有贡献的人!