Treatment of arrays within C #

xiaoxiao2021-03-06  110

Original: http://www.blogcn.com/User8/flier_lu/index.html? Id = 3318394

In the C / C code, a large amount of structure includes a common type and an array, such as the Image_Optional_Header structure of the definition PE file header structure is defined as follows:

The following is a program code: typedef struct _IMAGE_DATA_DIRECTORY {DWORD VirtualAddress; DWORD Size;} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16typedef struct _IMAGE_OPTIONAL_HEADER {WORD Magic; // ... DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} IMAGE_OPTIONAL_HEADER32, * PIMAGE_OPTIONAL_HEADER32;

In C / C , the use array in the structure is completely correct because these arrays will be part of the entire structure, and directly access the structure in the structure in the structure. But in the C # such language, you cannot use it directly, because the array is existing as a special reference type, such as definition:

The following program code is: public struct IMAGE_DATA_DIRECTORY {public uint VirtualAddress; public uint Size;} public struct IMAGE_OPTIONAL_HEADER {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; // ... public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }

In this defined array in the C # is wrong, it will get a CS0650 error when compiling:

The following is quoted:

Error CS0650: Grammatical error, error array declare. To declare the hosted array, the rank specifier should be in the variable identifier.

If you do a similar definition syntax of the reference type in C #, such as

The following program code is: public struct IMAGE_OPTIONAL_HEADER {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; // ... public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY [] DataDirectory = new IMAGE_DATA_DIRECTORY [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];}

Get a CS0573 error:

The following is quoted:

ERROR CS0573: "Image_Optional_Header.dataDirectory": There is no instance field initial value setting item in the structure.

Because the structure is unable to include the initialization of the reference type, this is different from the initialization of the Class. Thus, the initialization of the array can only be placed in the constructor, and the structure does not have the default constructor without parameters, it is trouble, huh, huh, 以下 以下 为 程序 代 代: public struge_optional_header {public const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY [] DataDirectory; public IMAGE_OPTIONAL_HEADER (IntPtr ptr) {Magic = 0; NumberOfRvaAndSizes = 0; DataDirectory = new IMAGE_DATA_DIRECTORY [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];}}

This looks like it seems to be made, but if you use Marshal.SizeOf (typeof (Image_Optional_Header), you will find that its length is different from the length defined in C / C . The problem is still in the architecture in the structure, although this array is defined in the structure, but in this structure only one pointer to the image_data_directory [] array type type, this should be saved in the array content of the DataDirectory unknown, is hosted Pile.

So the problem becomes how to put an array of reference types and placed in a structure of a value type.

There are many ways to solve, such as the length of explicitly specifying the structure through structlayout:

The following program code is: [StructLayout (LayoutKind.Sequential, Size = XXX)] public struct IMAGE_OPTIONAL_HEADER {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY DataDirectory;}

Note that SIZE in StructLayout is the length of the entire structure because the DataDirectory is already the last field, so the 15 elements of the array are stored in unnamed stack spaces. When you use, you need to read the entire structure at once, and then use the pointer operation of the UNSAFE code to access another array element behind the DataDirectory field.

The advantage of this method is to define simple, but the pointer operation code that needs to be rely on Unsafe is required, and the array field must be in the final limit. Of course, it is also possible to explicitly specify the unknown of each field to simulate multiple structural embedded groups, but this requires manual calculation of each field offset, trouble.

Another solution is to explicitly define the location of array elements through Marshal, such as

The following program code is: [StructLayout (LayoutKind.Sequential, Pack = 1)] public struct IMAGE_OPTIONAL_HEADER {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; public uint NumberOfRvaAndSizes; [MarshalAs (UnmanagedType.ByValArray, SizeConst = IMAGE_NUMBEROF_DIRECTORY_ENTRIES)] public Image_data_directory;} This method is relatively elegant, and the property supported by the MARSHAL mechanism is defined to define the array semantics, and the use of ordinary array is not too big. The above array definition is compiled into an IL definition:

The following is the program code: .field public marshal (fixed array [16]) ValueType Image_Data_directory [] DataDirectory

Although the type is also valueetype image_data_directory [], this array has changed from the reference semantic to the value semantic. However, this is still subject to some restrictions, such as can't be multi-layer nested, and the performance is affected during use.

In addition to the above two kinds of solutions to the structure definition itself, it is also possible to make an article from the operation of the structure.

In addition to access to the array of structures, the main operation type is to read the entire structure from the memory block or input stream, so it can completely use CLR to improve binary sequence support, complete the custom serialization function. Data loading and saving, such as:

The following is a program code: [Serializable] public struct IMAGE_OPTIONAL_HEADER: ISerializable {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY [] DataDirectory; public IMAGE_OPTIONAL_HEADER (IntPtr ptr) {Magic = 0; NumberOfRvaAndSizes = 0 ; DataDirectory = new IMAGE_DATA_DIRECTORY [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} [SecurityPermissionAttribute (SecurityAction.Demand, SerializationFormatter = true)] public virtual void GetObjectData (SerializationInfo info, StreamingContext context) {// complete serialization}}

Such a solution can be fully separated from the loading and storage of the structure, and the internal manifestation of the structure is completely separated. Although the structure is stored internally only an array reference, the user does not need to care. But the disadvantage is that the corresponding serialized support code must be written for each structure, writing and maintenance is more troublesome.

Similar to this idea is a solution I prefer, and the base class is uniformly processed by a public tool base class, such as:

The following program code is: public class IMAGE_OPTIONAL_HEADER: BinaryBlock {public const int IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; public ushort Magic; public uint NumberOfRvaAndSizes; public IMAGE_DATA_DIRECTORY [] DataDirectory = new IMAGE_DATA_DIRECTORY [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} Note that the original has been changed here struct class Because this approach has no need to have a memory model of the fixed value type. BinaryBlock is a public tool base class, which is responsible for providing type load and storage capabilities through Reflection, such as

The following program code is: public class BinaryBlock {private static readonly ILog _log = LogManager.GetLogger (typeof (BinaryBlock)); public BinaryBlock () {} static public object LoadFromStream (BinaryReader reader, Type objType) {if (objType.Equals ( TypeOf (char)) {return reader.readchar ();} else.equals (typeof (byte))) {return reader.readbyte ();} // ... else if (Objtype.equals (Typeof ())) {RETURN Reader.Readdouble ();} else if (objtype.isaRray) {// Handling array} else {foreach (FieldInfo Field in classtype.getfields ()) {Field.SetValue (Obj, LoadFromstream (...));}} return true;} public bool loadingfromstream (stream stream) {return loadingfromstream (new binaryreader (stream), this);}}

LoadFromStream is a nested method, which is responsible for loading the corresponding value from the stream based on the specified field type. When using the entire type, you will automatically process all the fields of the REFLECTION mechanism, all fields of the class, can be directly processed directly if there is a nested definition. With this method, the definition of type itself basically does not need to worry about load and storage mechanisms, as long as it is inherited from a binaryBlock type. Interested friends can also extend this class and support binary serialization mechanisms.

In addition, C # 2.0 provides a new Fixed Array mechanism in order to solve such problems, supports arrays that directly define inline semantics in the structure, such as

The following is program code: struct data {int header; fixed int value [10];

This structure translates array fields into an external value type structure when compiling. To achieve a suitable spatial layout, such as

The following program code is: .class private sequential ansi sealed beforefieldinit data extends [mscorlib] System.ValueType {.class sequential ansi sealed nested public beforefieldinit ' e__FixedBuffer0' extends [mscorlib] System.ValueType {.pack 0 .size 40 .custom instance void [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute ::. ctor () = (01 00 00 00 [img] /images/wink.gif [/ img] .field public int32 FixedElementField} // end of class ' e__FixedBuffer0' .field public int32 header .field public valuetype data / ' e__FixedBuffer0' values ​​.custom instance void [mscorlib] System.Runtime.CompilerServices.FixedBufferAttribute ::. ctor (class [mscorlib] System.Type , INT32) = (...)} // end of class data can see the value of the value of the value into a value, and the value type itself uses the idea of ​​the first solution similar to the first solution, forced limiting structure length. In use, it is also a UNSAFE operation similar to the first solution, such as a pointer operation that is compiled into a UNSAFE in this array:

The following is the program code: // Compile before compilation for (int i = 0; i <10; i ) D.VALUES [i] = i; // compile for (int i = 0; i <10; i ) & data1 .values.fixedelementfield [(INTPTR) i) * 4)] = i;

Unfortunately, this way must be compiled by unsafe because they are implemented by unsafe. And only the nested definition of the first level can be handled if the definition of image_optional_header will get a CS1663 error:

The following is the program code: Error CS1663: Fixed Size Buffer Type Must Be One of the Following: Bool, Byte, Short, Int, Long, Char, Sbyte, Ushort, Uint, Ulong, Float or Double

Eric Gunnerson has articles,

Arrays Inside of structures, briefly describes this limited grammatical enhancement syntax in C # 2.0.

转载请注明原文地址:https://www.9cbs.com/read-124462.html

New Post(0)