2013-03-25 129 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