C# 與C++的數據轉換


 

一、類型轉化

下面重點羅列下常用的類型轉化。

C++類型

C#類型

備注說明

Int

Int16、Int32

沒有懸念,直接轉化

Uint

UInt16、Uint32、int

在程序中,不太清楚是,就可以直接對應為int

Long

Int32

Long相對int就定型了,對應的就是Int32

DWORD(unsigned long)

Uint32

 

WORD(unsigned short)

Uint16

這是對WORD的認知。

Byte(Unsigned char)

Byte

DECIMAL

Decimal

位數轉化

BOOL

bool

 

char

char

這種沒有加指針,比較容易,直接對應入座

Handle(void *)

Intptr

函數中為窗口句柄,c#就是默認的為Intptr

HMODULE

Intptr

同上

HISTANCE

Intptr

同上

Int *、long *

Ref int、ref long

這種整形指針,在程序中是為了引用,所以在c#中對應的是ref,所以在關鍵詞之前加入ref.

Int &.long &

Ref int 、ref long

解釋同上,當然在關鍵詞加入 out,也是可以的

Char *(LPSTR、Pchar)、const char *(LPCSTR)、

String

也是為了獲取數據,在c#中string在應用中就是引用,所以直接改為string即可。Intptr也可以,不提倡。

Byte *

Ref byte、byte[]

程序byte * 是為了獲取類型為byte數據,在C#則用byte數組獲取存儲數據。String也可以,但是不提倡,關鍵看看獲取的數據,做什么用

GUID

Guid

 

Char[],byte[],in[]

可對應找指針類型對一個的轉化

Char[],byte[],int,這種在c++中應用時,先初始化數組,然后定義一個指針指向數據地址,然后訪問,所以在轉化是,在對應為char*》string , int[]>int * > intptr

Char **,byte **

Intptr

這種雙指針的調用,一般是訪問二位數組,所以我們直接處理為Intptr,當然intptr和之前不一樣,需要處理,可以看見例子說明。

結構體 * 變量名、結構體 &變量名。

Ref 結構體 變量名、intptr

在結構體引用,或者傳入值c++一般是用指針,在c#中,用ref代替。當然intptr也可以,但是不太方便。

 

 

通常在只要你選擇在win32運行環境中找到相匹配的CLR(公共語言運行庫,負責資源管理:內存分配和回收,並保證應用和底層操作系統之間有必要分離)類型,就可應正常工作。當然也有例外:BOOL在c++中發現其實為int型,所以轉化為int,而不是bool。

指針參數,在winAPI許多函數中將指針作為一個或者多個參數。指針的作用是存儲數據的地址,而不是數據。指針的加入,增加了數據的復雜性,同時增加數據靈活性,實現數據的傳入傳出,如果只是值類型應用只能是傳入數據。在應用中如果沒有指針,您可以直接通過值在線程堆棧中傳遞數據。有了指針,可以通過引用傳遞數據,將數據的內存地址推入到線程堆棧中,然后函數通過內存地址間接訪問數據。在c#用ref、out定義為類似指針作用關鍵詞。out是ref一個參數規范,實際上他們在運行中產生相同的機器碼,out作用為了讓調用者明白,數據只是傳出,ref表明數據傳入也是獲取。托管代碼中ref、out參數另一個很好用的是,可以作為結構體、類、數組提供一個地址供調用。只有在發現ref或out參數不符合需要情況下,才會封裝成更復雜的CLR類型。

在windows API中會有窗口句柄的獲取或者賦值,其方法的傳遞是不透明的,如handle、void *、histance等。

少數情況下,API 函數也將不透明指針定義為 PVOID 或 LPVOID 類型。在 Windows API 的定義中,這些類型意思就是說該指針沒有類型。當 一個不透明指針返回給您的應用程序(或者您的應用程序期望得到一個不透明指針)時,您應該將參數或返回值封送為 CLR 中的一種特殊類型 — System.IntPtr。當您使用 IntPtr 類型時,通常不使用 out 或 ref 參數,因為 IntPtr 意為直接持有指針。

在CLR類型系統中intptr是一種特殊的屬性,沒有固定的大小,在運行時再綁定,依據操作系統的正常指針而定。這意味着在 32 位的 Windows 中,IntPtr 變量的寬度是 32 位的,而在 64 位的 Windows 中,實時編譯器編譯的代碼會將 IntPtr 值看作 64 位的值。當在托管代碼和非托管代碼之間封送不透明指針時,這種自動調節大小的特點十分有用。然而,當使用 Windows API 函數時,因為指針應是不透明的,所以除了存儲和傳遞給外部方法外,不能將它們另做它用。這種“只限存儲和傳遞”規則的兩個特例是當您需要向外部方法傳遞 null 指針值和需要比較 IntPtr 值與 null 值的情況。為了做到這一點,您不能將零強制轉換為 System.IntPtr,而應該在 IntPtr 類型上使用 Int32.Zero 靜態公共字段,以便獲得用於比較或賦值的 null 值。

封送文本,主要是指在獲取數據時,數據可能是存儲在char數組中,如果我們用string接收時,有可能為亂碼。所以在函數調用過程中,當char *,char[]是作為輸入數據時,可以改為string。當作為數據傳出時,則要好好考慮了,有時需要改為char []。在c+程序中,就是在c中字符串實際上是只是一個字符值數組,通常為null,大多數windows API函數是按照對於ansi,將其作為字符值數組(比較常用),對於unicode,將其作為寬字符值數組。有時獲取的數據為亂碼時,可能就是需要轉為unicode,就解決了。大多數windows API函數都帶有LPTSTR或者LPCTSTR值。他們分別是可修改和不可修改的緩沖區,包含以null結束的字符數組。“C”代表const,意味數據不會傳遞到函數外部。“T”代表該參數可以是Unicode和ANSI,在CLR運行中取決你選擇的字符集和底層操作系統的字符集.。所以函數聲明時,加上DllImportAttribute 為CharSet.Auto就可以了。如果字符串參數只用作輸入,則使用 System.String 類型。在托管代碼中,字符串是不變的,適合用於不會被本機 API 函數更改的緩沖區。如 果字符串參數可以用作輸入和/或輸出,則使用 System.StringBuilder 類型。StringBuilder 類型是一個很有用的類庫類型,它可以幫助您有效地構建字符串,也正好可以將緩沖區傳遞給本機函數,由本機函數為您填充字符串數據。一旦函數調用返回,您只 需要調用 StringBuilder 對象的 ToString 就可以得到一個 String 對象。

CharSet的各變量對char以及char[]的影響如下:
ANSI:char以及char[]占一個字節
AUTO:char以及char[]占兩個字節
UNICODE:char以及char[]占兩個字節

總體原則可以總結為:

1、在c++常用的基本類型(數值類型、字節類型)直接轉化到c#中的數值類型。(原則是字節數,確定好)

2、在c++常用的指針類型(數值類型*、字節類型*)則轉化為c#中的ref 數值類型、ref 字節類型。但是在常用時,針對char * ,轉化為string。

3、在c++常用的構造類型(結構體、數組、枚舉類型、共用體)行對比較復雜。枚舉和共用體直接復制就可以用,結構體的聲明隨后重點講,在函數調用時,如果為結構體 * 變量名,則為 ref 結構體 變量名。數組在 函數調用,可以直接寫為數組名,也可以寫為Intptr。

二、結構體

 

1、結構體的重定義。

 

在c++中會有很多結構體,結構體內有各種各樣的數據類型,所以就牽涉到數據類型的轉化,同時在通過結構體獲取到數據后,也牽涉到編碼轉化問題。

結構體類型和類類型在語法上有很多相似之處,他們都是一種數據結構,都可以包括數據成員和方法成員。

結構體和類區別:

1、結構體是值類型,它在棧中分配空間;類是引用類型,他在堆中分配空間,棧存儲的是引用。

2、結構體類型直接存儲成員數據,類中數據類型存在堆中,然后通過在棧中引用,訪問數據。因為結構體是值類型,直接存儲,因此當對象的主要成員為數據切不大時,使用結構體效率更高。

3、結構體直接包含自己的數據,每個結構體都保存一份數據,在程序聲明兩個結構體對象,改變其中一個,另一個數據不變,但是類是引用,則另一個數據會改變。

4、結構體是值類型,不能初始化為null,復制時則數據全部復制。;類中的復制是引用的復制,數據較大時,結構體復制則效果不是很好。

 

結構和類的適用場合分析:

 

  1、當堆棧的空間很有限,且有大量的邏輯對象時,創建類要比創建結構好一些;

  2、對於點、矩形和顏色這樣的輕量對象,假如要聲明一個含有許多個顏色對象的數組,則CLR需要為每個對象分配內存,在這種情況下,使用結構的成本較低;

  3、在表現抽象和多級別的對象層次時,類是最好的選擇,因為結構不支持繼承。

  4、大多數情況下,目標類型只是含有一些數據,或者以數據為主。

 

結構體的聲明、初始化、引用在c#還是很重要的,下面根據代碼進行分析。

 

[cpp]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. //C++的結構體  
[cpp]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1. //錄像索引列表文件  
  2. typedef struct tagINDEX_INFO  
  3. {  
  4.     DWORD dwStartTime;              //錄像開始時間  
  5.     DWORD dwEndTime;                //錄像停止時間  
  6.     BYTE  btFileType;                   //文件類型  
  7.     BYTE  btFileStatus;             //文件狀態  
  8.     BYTE  Reserved[2];              //預留,LMC向NVR請求回放時Reserved[0]標識NVR發送速度,Reserved[1]存放錄像倒放標志  
  9.       
  10.     BYTE  btMAC[6];                 //設備MAC地址  
  11.     WORD  wChan;                    //設備通道  
  12.     DWORD dwIP1;                    //設備IP1  
  13.     DWORD dwIP2;                    //設備IP2,公網模式下,存儲此文件所在的NVR的IP  
  14.     DWORD dwIP3;                    //設備IP3,V3061用來存儲錄像片段在錄像文件的偏移量,勿動  
  15.     DWORD dwIP4;                    //設備IP4,V3061用來錄像文件名,勿動  
  16.     DWORD dwFileOffset;             //文件偏移,用於文件下載時斷點續傳和定位  
  17.     DWORD dwReserved;               //預留,3070有用到,不要動它  
  18. }INDEX_INFO, *LPINDEX_INFO;  

 

C#結構體

 

[cpp]  view plain copy print ? 在CODE上查看代碼片 派生到我的代碼片
 
  1.   

 //錄像索引列表文件
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi,Pack = 1)]
        public struct NET_INDEX_INFO
        {
            public UInt32 dwStartTime; //錄像開始時間
            public UInt32 dwEndTime; //錄像停止時間
            public byte btFileType; //文件類型
            public byte btFileStatus; //文件狀態
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte [] Reserved; //預留,LMC向NVR請求回放時Reserved[0]標識NVR發送速度,Reserved[1]存放錄像倒放標志
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
            public byte [] btMAC; //設備MAC地址
            public UInt16 wChan; //設備通道
            public UInt32 dwIP1; //設備IP1
            public UInt32 dwIP2; //設備IP2,公網模式下,存儲此文件所在的NVR的IP
            public UInt32 dwIP3; //設備IP3,V3061用來存儲錄像片段在錄像文件的偏移量,勿動
            public UInt32 dwIP4; //設備IP4,V3061用來錄像文件名,勿動
            public UInt32 dwFileOffset; //文件偏移,用於文件下載時斷點續傳和定位
            public UInt32 dwReserved; //預留,3070有用到,不要動它
        }

 

上面成員前面必須添加public,因為默認是private。

2、StructLayout特性

公共語言運行庫利用StructLayoutAttribute控制類或結構的數據字段在托管內存中的物理布局,即類或結構需要按某種方式排列。如果要將類傳遞給需要指定布局的非托管代碼,則顯式控制類布局是重要的。它的構造函數中用 LayoutKind值初始化 StructLayoutAttribute 類的新實例。 LayoutKind.Sequential 用於強制將成員按其出現的順序進行順序布局。
System.Runtime.InteropServices.StructLayout   允許的值有StructLayout.Auto   StructLayout.Sequential   StructLayout.Explicit.  在應用中為了數據順利傳入,一般是用StructLayout.Sequential,意味着結構體體內數據傳入的格局按照聲明一樣。 StructLayout.Explicit需要用FieldOffset()設置每個成員的位置這樣就可以實現類似c的公用體的功能。
[StructLayout(LayoutKind.Explicit)] 
struct S1
{
  [FieldOffset(0)]
  int a;
  [FieldOffset(0)]
  int b;
}
這樣a和b在內存中地址相同

StructLayout特性支持三種附加字段:CharSet、Pack、Size。     
·   CharSet定義在結構中的字符串成員在結構被傳給DLL時的排列方式。可以是Unicode、Ansi或Auto。     
  默認為Auto,在WIN   NT/2000/XP中表示字符串按照Unicode字符串進行排列,在WIN   95/98/Me中則表示按照ANSI字符串進行排列。     
·   Pack定義了結構的封裝大小。可以是1、2、4、8、16、32、64、128或特殊值0。特殊值0表示當前操作平台默認的壓縮大小。 

3.MarshalAs的使用

MarshalAs屬性指示如何在托管代碼和非托管代碼之間封送數據。
[MarshalAs(UnmanagedType unmanagedType, 命名參數)]

 

常用的UnmanagedType枚舉值:(詳細內容查MSDN)

BStr   長度前綴為雙字節的 Unicode 字符串;

LPStr  單字節、空終止的 ANSI 字符串。;

LPWStr  一個 2 字節、空終止的 Unicode 字符串;

ByValArray 用於在結構中出現的內聯定長字符數組,應始終使用MarshalAsAttribute的SizeConst字段來指示數組的大小。常用的是數組對應的為ByAvlArray,string對應的是ByValStr。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM