2013-03-25 76 views
2

编辑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被传递到一个消息。但是,这并不能表明人们的期望。 NodeType的值仍然正确。对于DOFValue显示的值是0,这导致我得出结论:在分配值时出现了严重错误。我不知何故有时设法得到一个长数值的方法,这个数字与0不一样。但是我在最后的测试中无法再现这个错误。 inp的可能值为{2,1,1,-451.387},所以第一个1-451.387被遗忘。

有谁知道我在做什么错或如何解决这个问题?

非常感谢提前!

编辑:

改变%i%li但结果并没有改变。谢谢放松!

我正在用Dev-Cpp使用MinGW开发这个dll(不幸),因为我无法说服Visual Studio 2012 Pro正确编译它。尽管原始资料的文档说明它是纯粹的ANSI-C。这有点让我感到困惑,因为我无法用Dev-Cpp正确调试这个dll。因此消息框。

编辑2:

作为尼尔汤森建议的,我切换到经过参考。但是这也没有解决问题。当我直接访问结构中的值时,一切都很好。当我将它们分配给变量时,有些会丢失。

关于我如何调用函数的简短通知。该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#中传递很长时间会提供最好的兼容性。因此,sprintf组织可以简化为这样一个问题:“长多长的格式标识符是什么?”。

这实际上很简单,它是%lli。所以我可以公布drumroll我的问题真的解决了!

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

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

+0

'long'在你的C代码中代表什么类型?在C#中,输入'long'是一个64位整数,但在许多C实现中它是一个32位整数。 – supercat 2013-03-26 19:31:52

+0

在我的C代码中,我有很长的时间(实际上它是一个'FR_INT4',它是 - 通过编译器标志设置为'#define FR_INT4 long long')从C#传递一个'int' - 这是我从这里得到的 - 一旦传递给C,真的很久了。或者我错了,'FR_INT4'真的很长,所以我应该从C#中传出一段长时间? =>是的,我应该! (我会更新我的帖子,但再次;-)感谢您指点我! – lhiapgpeonk 2013-03-27 07:21:04

+0

C#类型'long'是'System.Int64'的别名。我建议所有依赖内存布局的代码应该使用明确标识所涉及项目大小的类型,并且尽可能地尝试按照其大小的倍数对齐所有具有二次大小的基元。避免使用位移4,12,20等字节的“double”或“Int64”项)。 – supercat 2013-03-27 16:17:30

回答

0

要弄清这个作为回答:

我的结构实际上是:

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

要求long从C#(而不是int,因为我以前认为的)传递。通过调试,我发现值的分配表现得应该如此,问题在sprintf之内。如果我使用%lli作为格式标识符,即使此问题已解决。

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

是我需要使用的声明。所以再次感谢每个人的贡献!

1

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

+0

这没有帮助,我会编辑我的帖子,包括编译器 – lhiapgpeonk 2013-03-25 14:39:53

+0

但无论如何谢谢! (我应该在评论tss时更有礼貌......) – lhiapgpeonk 2013-03-26 08:26:45

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回报的任何更改操作。

+0

谢谢,但那也行不通。我会再次更新我的问题,包括mor的细节。 – lhiapgpeonk 2013-03-26 08:29:41

+0

我对c#不是很了解,但是在作业之后是否使用(除了打印)'DOF'和'wert'?是否有可能你不使用它们,所以优化编译器不费心去做这个任务?您是否一次在调试器行中运行代码以查看发生了什么? – 2013-03-26 11:42:45

+0

在我的实际代码中,我确实使用了这些值(至少我打算这么做)。我认为这与C#无关,因为这些值正确地到达了我的C代码。至于调试,我目前正试图说服VS接受我的C代码,所以我可以使用VS作为调试器。或者你知道任何方式可以与Dev-Cpp一起舒适吗?我会及时通知你的! – lhiapgpeonk 2013-03-26 12:29:32