2011-02-23 60 views
1

我有一個DBase IV數據庫。每行都有一個帶有ASCII編碼字符串的備註字段,該字符串包含兩個序列化的borland C++結構。我能夠使用OleDb獲取數據,使用ASCIIEncoding類將其重新編碼爲ascii,使用BinaryReader將其轉換爲字節,然後使用Marshal.PtrToStructure將其轉換爲C#結構。我得到的數據是正確的,但是當數據庫被轉換爲c#時,數據庫中的任何浮點數都是完全錯誤的。例如,值1149.00強制轉換爲764.9844,但像64.00這樣的值強制轉換。我可以發佈一些代碼和結構,但我想我首先試圖保持它的簡短。我知道浮點數只能精確到7位數,但我很困惑,爲什麼我看到這個數字是因爲數值低於這個限制。Marshal C++ float to C#float precision problem

編輯:

struct cplusplusstruct // from the c++ code 
{ 
    int Number; 
    float P; 
    float ZP; 
    float Hours; 
    int Month; 
    int Day; 
    int Year; 
    int Hour; 
    int Minute; 
    int Second; 
    ULONG UPCTime; 
    int B; 
    char Name[21]; 
    float L; 
    float H; 
    float S; 
} 


[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct csharpstruct //The C# struct I created 
{ 
    public int Number; 
    public float Pr; 
    public float ZP; 
    public float Hours; 
    public int Month; 
    public int Day; 
    public int Year; 
    public int Hour; 
    public int Minute; 
    public int Second; 
    public UInt32 UPCTime; 
    public int B; 
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 21)] 
    public string Name; 
    public float L; 
    public float H; 
    public float S; 
} 


//OLE DB Connection and query ... 

//Casting data to struct 
ASCIIEncoding encoding = new ASCIIEncoding(); 
byte[] blob = encoding.GetBytes(memoString); 
MemoryStream memoryStream = new MemoryStream(blob); 
BinaryReader binaryReader = new BinaryReader(memoryStream); 

int dataSize = Marshal.SizeOf(typeof(csharpstruct)); 
GCHandle handle = GCHandle.Alloc(binaryReader.ReadBytes(dataSize), GCHandleType.Pinned); 
csharpstruct data = (csharpstruct) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(csharpstruct)); 

編輯:下面是讀取數據就好了,但沒有任何使用鑄造的Java代碼。

org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath); 
org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath); 
MemoField m = (MemoField) dbf.getField("MEMOFIELD"); 

Charset charset = Charset.forName("US-ASCII"); 
CharsetDecoder decoder = charset.newDecoder(); 
ByteBuffer trendBytes = ByteBuffer.wrap(m.getBytes()); 
trendBytes.order(ByteOrder.LITTLE_ENDIAN); 
trendBytes.getInt(); 
trendBytes.getFloat(); 
+0

小心發佈一些代碼片段? – 2011-02-23 18:28:10

+0

C++結構是雙重還是編譯爲使用不同的浮點模型? – plinth 2011-02-23 18:35:24

+0

@Sparkie - 如果它會幫助,我會 – Carlosfocker 2011-02-23 18:39:33

回答

0

我無法直接解決問題。問題似乎來自我使用的OLE數據提供者。從數據庫中收回的數據與xBaseJ提供的數據略有不同。我最終使用IKVM.NET將xBaseJ轉換爲CLI字節碼。這使我可以用xBaseJ閱讀器替換OLE數據提供者。其餘的代碼保持不變。

3

你在你的C#結構中有Pack = 1,但沒有說你的C++結構是否打包。由於您的浮動數據(21個字符的字符串)之前有一個奇數大小的字段,可能會導致問題,並且意味着您的浮動數據正被讀取錯誤對齊。之前的所有內容都有4個字節長,因此打包不太可能會導致您的問題。在進一步研究之前,我會確保包裝符合C#和C++。

+0

C++頭文件指定#pragma pack(1)。 – Carlosfocker 2011-02-24 16:16:18

+0

另請注意,此問題出現在結構中的所有浮點數上。如果價值在1000年,它會變得混亂。如果不是,那麼我會得到正確的數據。 – Carlosfocker 2011-02-24 16:38:05