2008-09-24 5 views
59

Tôi đang dịch thư viện được viết bằng C++ thành C# và từ khoá 'union' tồn tại một lần. Trong một cấu trúc.Liên minh C++ trong C#

Cách dịch chính xác vào C# là gì? Và nó làm gì? Nó trông giống như thế này;

struct Foo { 
    float bar; 

    union { 
     int killroy; 
     float fubar; 
    } as; 
} 
+0

Có thể an toàn hơn nhưng khi bạn tương tác với thư viện C cung cấp các loại cấu trúc dữ liệu này, quyết định này sẽ phá vỡ ngay cả cấu trúc C/C++ thô sơ của bạn. Tôi đang cố gắng để đối phó với một cái gì đó như thế này: struct LibrarySType {AnotherType * anotherTypeBuff; int oneSetOfFlags; int anotherSetOfFlags; union {struct {int structMember1; ...} oneUseOfThisLibraryType; struct {char * structMember2; ...} anotherUseOfThisLibraryType; ...} u; int64 * moreStuff; ...Bây giờ tôi không tạo ra cấu trúc dữ liệu thông minh này, nhưng nó là một phần của API của nhà cung cấp, tôi cần –

Trả lời

63

Bạn có thể sử dụng bố trí lĩnh vực rõ ràng cho điều đó:

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion 
{ 
    [FieldOffset(0)] public float bar; 
    [FieldOffset(4)] public int killroy; 
    [FieldOffset(4)] public float fubar; 
} 

chưa được kiểm tra. Ý tưởng là hai biến có cùng vị trí trong cấu trúc của bạn. Tất nhiên bạn chỉ có thể sử dụng một trong số họ.

Mọi thông tin về công đoàn trong struct tutorial

+2

Lưu ý rằng điều này sẽ chỉ hoạt động nếu các kiểu liên quan là các kiểu nguyên thủy (như int và float). Một khi các đối tượng có liên quan, nó sẽ không cho phép bạn. – Khoth

+9

Tính năng này có hoạt động với các loại giá trị (như enum) hay chỉ các kiểu nguyên thủy không? –

+1

Nếu bạn có các loại phức tạp khác, loại thứ hai có thể là thuộc tính chuyển đổi sang/từ cái kia. Phụ thuộc vào cách sử dụng của Liên minh và cách nó được sử dụng trong mã khác mà bạn đang chuyển. – AaronLS

3

Trong C/C++ đoàn được sử dụng để che phủ các thành viên khác nhau trong trí nhớ cùng, vì vậy nếu bạn có một sự kết hợp của một int và một căn hộ cả hai đều sử dụng cùng một 4 byte của bộ nhớ, rõ ràng bằng văn bản cho một người khác bị hỏng (vì int và float có bố trí bit khác nhau).

Trong MS .net đi kèm với lựa chọn an toàn hơn và không bao gồm tính năng này.

EDIT: trừ interop

+0

có thể do .NET là cấp cao hơn và bạn có thể không phải lo lắng về việc tuần tự hóa dữ liệu một cách rõ ràng và chuyển giữa các máy nhỏ và máy tính lớn. Công đoàn cung cấp một cách tốt đẹp để chuyển đổi, bằng cách sử dụng các trick một bình luận trước đó lưu ý. – tloach

2

Cá nhân, tôi sẽ bỏ qua các UNION tất cả cùng nhau và thực hiện Killroy và Fubar như lĩnh vực riêng biệt

public struct Foo 
{ 
    float bar; 
    int Kilroy; 
    float Fubar; 
} 

Sử dụng UNION tiết kiệm 32 bit của bộ nhớ được phân bổ bởi int. ... sẽ không thực hiện hoặc phá vỡ một ứng dụng trong những ngày này.

+7

điều này có thể không hoạt động tùy thuộc vào cách nó được truy cập bởi các phần khác của thư viện, trong một số trường hợp, bạn có thể ghi vào một thể hiện và đọc từ trường kia để có cùng dữ liệu nhưng ở định dạng hơi khác, chức năng đó sẽ bị hỏng bạn chia nó thành hai biến riêng biệt – KPexEA

+0

@KPexEA Tôi đồng ý. Tuy nhiên, nếu mặt khác, đó là loại hình công đoàn mà một số cờ chỉ ra trường nào trong hai trường là một trường thích hợp, thì điều này sẽ hoạt động tốt. Tôi nghĩ điều thực sự quan trọng là hiểu cách sử dụng và mục đích của công đoàn trong từng trường hợp, trước khi quyết định cách chuyển nó. – AaronLS

22

Bạn thực sự không thể quyết định cách giải quyết vấn đề này mà không biết điều gì đó được sử dụng như thế nào. Nếu nó chỉ được sử dụng để tiết kiệm không gian, thì bạn có thể bỏ qua nó và chỉ sử dụng một cấu trúc.

Tuy nhiên, đó thường không phải là lý do tại sao các công đoàn được sử dụng. Có hai lý do phổ biến để sử dụng chúng. Một là cung cấp 2 hoặc nhiều cách để truy cập cùng một dữ liệu. Ví dụ, một liên minh của một int và một mảng 4 byte là một (nhiều) cách để tách các byte của một số nguyên 32 bit.

Khác là khi dữ liệu trong cấu trúc đến từ nguồn bên ngoài, chẳng hạn như gói dữ liệu mạng. Thông thường, một phần tử của cấu trúc kèm theo liên minh là một ID cho bạn biết hương vị của liên minh nào có hiệu lực.

Trong cả hai trường hợp này, bạn có thể bỏ qua công đoàn một cách mù quáng và chuyển đổi nó thành cấu trúc trong đó hai (hoặc nhiều trường) không trùng khớp nhau.

+3

Những gì tôi nghĩ là quan trọng trong câu trả lời của Steve, là bạn thực sự cần phải hiểu cách sử dụng của công đoàn cụ thể mà bạn đang chuyển. Có thể có các cấu trúc khác trong C# sẽ đáp ứng nhu cầu một cách thanh lịch hơn. – AaronLS

+0

+1 cho cách sử dụng thông thường – mbx

1

Nếu bạn đang sử dụng union để ánh xạ các byte của một trong các loại này đến loại khác thì trong C# bạn có thể sử dụng BitConverter để thay thế.

float fubar = 125f; 
int killroy = BitConverter.ToInt32(BitConverter.GetBytes(fubar), 0); 

hoặc;

int killroy = 125; 
float fubar = BitConverter.ToSingle(BitConverter.GetBytes(killroy), 0);