C # Sharp experience 18th non-security code

Source: Internet
Author: User
C # Sharp experience

Nanjing Institute of Posts and Telecommunications Li Jianzhong ( Lijianzhong@263.net.cn )

Lecture 2 Non-Security Code

C # introduces a managed security programming method for. Net universal language runtime. Operations such as pointer access, variable address calculation, and object destruction are not allowed by C # In a hosted programming environment, which greatly improves the security of traditional C/C ++. However, things are often multidimensional. In addition to direct access to memory such as pointers, we also lose the convenience of things on some issues, for example, some interactions with the underlying operating system and access to memory ing devices. In some special tasks, we do not even want to introduce the "Uncertain System consumption" of automatic garbage collection ". C # introduce Unsafe code to meet these special needs.

Non-Security Code
??????? In Unsafe code, C # allows us to directly operate pointers, obtain the variable address, convert the pointer type to the integer type, and so on. Unsafe code is identified by the keyword "unsafe. The "/unsafe" option must be added to compile Unsafe code; otherwise, the compiler reports an error. The "unsafe" keyword can be added to the type (class, structure, interface, delegate) Declaration, Member (constructor, destructor, domain, method, attribute, event, indexer, operator) Declaration, and statement block enclosed by braces. The Unsafe code block is also called the unsafe context. Take a look at the following routine:

Using system;
Unsafe struct point // unsafe type
{
????? Public int * X, Y;

????? Public point (int * a, int * B)
????? {
????????? X =;
????????? Y = B;
?????}
}
Class Test
{
????? Public static void swap (ref int X, ref int y)
????? {
????????? Int;
????????? A = x; X = y; y =;
?????}

????? Public static unsafe void swap (ref int * X, ref int * Y) // unsafe Member
????? {
????????? Int *;
????????? A = x; X = y; y =;
?????}

????? Public static void main ()
????? {
????????? Int A = 1, B = 2;
????????? Unsafe // unsafe statement Block
????????? {
?????????????? Point Pt = new point (& A, & B); // Initialization
?????????????? Console. writeline ("Initial Value :");
?????????????? Console. writeline ("values :?? * PT. x = {0}, * PT. Y = {1} ", * PT. X, * PT. y );
?????????????? Console. writeline ("Address: Pt. x = {0}, Pt. Y = {1}", (INT) pt. X, (INT) pt. y );
??????????????
?????????????? Swap (ref * PT. X, ref * PT. Y); // exchange value
?????????????? Console. writeline ("after changing the value :");
?????????????? Console. writeline ("values :?? * PT. x = {0}, * PT. Y = {1} ", * PT. X, * PT. y );
?????????????? Console. writeline ("Address: Pt. x = {0}, Pt. Y = {1}", (INT) pt. X, (INT) pt. y );
????????????????????????????
?????????????? Swap (ref pt. X, ref pt. Y); // exchange address
?????????????? Console. writeline ("after address change :");
?????????????? Console. writeline ("values :?? * PT. x = {0}, * PT. Y = {1} ", * PT. X, * PT. y );
?????????????? Console. writeline ("Address: Pt. x = {0}, Pt. Y = {1}", (INT) pt. X, (INT) pt. y );
?????????}
?????}
}

Program output:
Initial Value:
Values :?? * PT. x = 1, * PT. Y = 2
Address: Pt. x= 1243332, Pt. Y = 1243328
After changing the value:
Values :?? * PT. x = 2, * PT. y = 1
Address: Pt. x= 1243332, Pt. Y = 1243328
After address change:
Values :?? * PT. x = 1, * PT. Y = 2
Address: Pt. x= 1243328, Pt. Y = 1243332

In the above program, we demonstrate three typical unsafe contexts. We use unsafe to modify the point structure type so that the pointer can be operated anywhere in the structure.
Note that the member declaration statement "Public int * X, Y;" declares that both X and Y are pointers to integers. In traditional C/C ++, both X and Y are required, add a star number (*) before "Y", for example, "Public int * X, * Y ;".
After unsafe modification is added to the swap method declaration in the test class, you can pass in pointer type parameters and perform pointer operations in the method body.
In the main function, we use the unsafe statement block processing method, which enables pointer access within the statement block. Two swap functions, one switching pointer pointing to the data and one switching pointer address, we can also see this from the output of the program.
It should be noted that "non-security code is not unsafe "! It only indicates that the memory is not managed by the automatic garbage collector, and we need to allocate and release the memory as we did in C/C ++.

Pointer type
??????? The pointer type is similar to the reference type in the previous hosted environment. The type itself does not contain data, and the data is contained in the memory block they direct. The pointer type is essentially different from the reference type in the hosting environment-the data block pointed to by the pointer is not tracked by the automatic garbage collector, the Data Objects pointed to by the reference handle are tracked and managed by the automatic garbage collector. In fact, the automatic garbage collector does not know the existence of pointers and their data!
??????? The pointer type contains the data type of the memory block to which it points. This data type is limited to "unmanaged type" and "Void type" in C ". The "unmanaged type" is defined as one of the following types:
1 .?? Sbyte, byte, short, ushort, Int, uint, long, ulong, Char, float, double, decimal and bool;
2 .?? Enumeration type;
3 .?? Custom structure type, whose member variables can only be "unmanaged type ";
4 .?? Pointer type.
As you can see, the "unmanaged type" cannot be a reference type. In fact, the memory block to which the pointer type points cannot be a reference type or a custom structure containing the reference type. But the reference type can contain the pointer type. Why? It is not difficult to understand this, because the reference type is automatically managed by the garbage collector, and the "unmanaged type" declared as pointing to the pointer is not managed by the automatic garbage collector!
??????? Although the pointer can use out and ref to express the address transfer (reference transfer) when passing parameters ), so that we can change the pointer variable itself (that is, the address of the variable) in the function. The swap function in the first example in this article does this. But like passing pointer parameters in C/C ++, if we change the pointer value to the address of the local variable in the function in such a function, when we exit the function, because the system often recycles these address spaces, the program will have undefined behavior. See the following example:

Using system;
Class Test
{
????? Unsafe static void F (Out int * Pi1, ref int * Pi2)
????? {
????????? Int I = 100;
????????? Int J = 200;
????????? PI1 = & I;
????????? PI2 = & J;
????????? Console. writeline (INT) PI1 + "," + (INT) Pi2 );
?????}
????? Unsafe static void main ()
????? {
????????? Int I = 10 ;????????
????????? Int * px1 = & I;
????????? Int * px2 = & I;
????????? Console. writeline (INT) px1 + "," + (INT) px2 );
?????????
????????? F (Out px1, ref px2 );

????????? Console. writeline (INT) px1 + "," + (INT) px2 );
????????? Console. writeline ("* px1 = {0}, * px2 = {1}", * px1, * px2 );
?????}
}

Program output:
1243332,1243332
1243304,1243308
1243304,1243308
* Px1 = 13249636, * px2 = 13253284
??????? Note that the results of the first three rows depend on the specific execution environment, and the results of the last row are undefined program behaviors. We can see that the storage space of the variable I in function f is recycled after exiting the function stack. the pointer variable px1 and px2 are not sure about the value. In view of this, we generally do not use out to modify the pointer type parameters. Only after determining that the changed address space will not be recycled after exiting the function can we use ref to modify the pointer type parameters.
??????? The pointer type can be converted to the integer type of the eight C # types, which must be explicitly converted in the form of brackets. The null type can also be used as a pointer, indicating that the address is 0 and does not point to valid data. There is also a clear conversion between pointers pointing to different data types (excluding void types. When the void * type is converted to another managed value needle type, it is clearly converted. Otherwise, if other pointer types are converted to void *, they are implicitly converted and can be automatically performed. C # it is not guaranteed that the conversion between pointer types is safe. You can use the exception capture mechanism of C # to handle this situation.
??????? Similar to C/C ++, pointer types can be involved in a considerable number of expression operations. In addition to the previous operations such as pointer lift (* P = value), address fetch (P = & value), and structure member acquisition operations (p-> value ), pointer Element Acquisition (P [0]), pointer increment and reduction operations (P ++, p --, ++ P, -- p ), sizeof (unmanaged-type), comparison between pointers, plus or minus operations between pointers and integers (INT, uint, long, ulong. These expression operations must be placed in the code of the unsafe flag; otherwise, compilation errors may occur.

FixedStatement
??????? From the perspective of memory management, variables in C # can be divided into two categories: fixed variables and movable variables. Fixed variables are usually hosted in the stack of method calls, and their memory is not managed by the automatic garbage collector.
Examples of fixed variables include local variables of the unmanaged type and Their instance domain members, value passing parameters of the unmanaged type, and variables created by raising pointers. One way to identify a fixed variable is to see if it can use the symbol & to get its address without any restrictions. Take a look at the following routine:

Using system;
Struct point
{
????? Public int X;
????? Public int y;
????? Public int Z;
}
Unsafe class test
{
????? Static void main ()
????? {
????????? Int integer = 100 ;???
????????? Printaddress (integer );

????????? Int * ptinteger = & integer;
????????? Console. writeline (INT) & (* ptinteger); // The variable created by the lift pointer

????????? Point point = new point ();
????????? Console. writeline (INT) & Point); // unmanaged local variable
????????? Console. writeline (INT) & point. X); // an instance Member of an unmanaged local variable
????????? Console. writeline (INT) & point. Y); // an instance Member of an unmanaged local variable
????????? Console. writeline (INT) & point. z); // an instance Member of an unmanaged local variable
?????}

????? Static void printaddress (int I)
????? {
????????? Console. writeline (INT) & I); // value passing parameter of the unmanaged type
?????}
}

??????? Movable variables are hosted in the managed heap, and their memory is fully managed by the automatic garbage collector. Examples of movable variables include instance domain members that reference type objects, static domain members of any type, referenced or output parameters, and array elements. You cannot directly use symbols to get the addresses of movable variables. C # supports the use of fixed statements to temporarily obtain the addresses of movable variables. This address is valid only in the block followed by fixed. Take a look at the following routine:

Using system;
Class myclass
{????
????? Public static int staticfield;
????? Public int instancefield;
}
Unsafe class test
{
????? Static void printaddress (int * point)
????? {
????????? Console. writeline (INT) Point );
?????}
????? Public static void main ()
????? {
????????? Myclass myobject = new myclass ();
????????? Int [] arr = new int [10];
????????? Fixed (int * P = & myclass. staticfield) printaddress (P );
????????? Fixed (int * P = & myobject. instancefield) printaddress (P );
????????? Fixed (int * P = & arr [0]) printaddress (P );
????????? Fixed (int * P = ARR) printaddress (P );
?????}
}

SizeofOperator
??????? The sizeof operator can be used to calculate the storage size of an unmanaged type during stack allocation. The result is an integer in bytes. The operation object of the sizeof operator is a hosted type. Variables cannot be used as parameters of the sizeof operator.
??????? For simple types in C #, because their storage space has been determined by the system, sizeof Returns their occupied bytes as constants. For a custom Enumeration type, sizeof returns the storage size of the base type specified by this enumeration type. If no base type is specified, C # Is a 32-bit integer by default. For the pointer type, the storage size is the same as the 32-bit integer type, and the natural sizeof returns 4 bytes. Take a look at the following routine:

Using system;
Enum myenum: byte
{
????? Beijing,
????? Shanghai,
????? Nanjing
}
Class Test
{
????? Public unsafe static void main ()
????? {
????????? Console. Write ("sizeof (sbyte): {0 }?? /T ", sizeof (sbyte ));
????????? Console. writeline ("sizeof (byte)" + sizeof (byte ));
????????? Console. Write ("sizeof (short): {0 }?? /T ", sizeof (short ));
????????? Console. writeline ("sizeof (ushort):" + sizeof (ushort ));
????????? Console. Write ("sizeof (INT): {0 }??? /T ", sizeof (INT ));
????????? Console. writeline ("sizeof (uint):" + sizeof (uint ));
????????? Console. Write ("sizeof (long): {0 }??? /T ", sizeof (long ));
????????? Console. writeline ("sizeof (ulong):" + sizeof (ulong ));

????????? Console. Write ("sizeof (char): {0 }??? /T ", sizeof (char ));
????????? Console. writeline ("sizeof (bool):" + sizeof (bool ));
????????? Console. Write ("sizeof (float): {0 }??? /T ", sizeof (float ));
????????? Console. writeline ("sizeof (double):" + sizeof (double ));

????????? Console. Write ("sizeof (myenum): {0 }??? /T ", sizeof (myenum ));
????????? Console. writeline ("sizeof (int *): {0 }??? /T ", sizeof (int *));
?????}
}

Program output:
Sizeof (sbyte): 1 ????????? Sizeof (byte) 1
Sizeof (short): 2 ????????? Sizeof (ushort): 2
Sizeof (INT): 4 ?????????? Sizeof (uint): 4
Sizeof (long): 8 ?????????? Sizeof (ulong): 8
Sizeof (char): 2 ?????????? Sizeof (bool): 1
Sizeof (float): 4 ?????????? Sizeof (double): 8
Sizeof (myenum): 1 ?????????? Sizeof (int *): 4 ?????????

For managed custom structure types, sizeof should consider the storage space arrangement of member variables of each domain when calculating its storage size. If structlayout features are not explicitly specified, the storage arrangement of Domain member variables hosting custom structure types will be the responsibility of CLR runtime, in this case, the storage space of the structure is usually filled to arrange and alignment. That is to say. It is worth noting that the Declaration Order of member variables is different, which may lead to different arrangements for them during CLR runtime, and different filling behaviors may occur, it may also lead to different sizeof return values. For the managed custom structure explicitly specified by structlayout features, sizeof should consider alignment and padding while arranging according to the specified requirements. Take a look at the following routine:

Using system;
Using system. runtime. interopservices;

Struct mystruct1
{
????? Public byte mybyte; // 1 byte
????? Public short myshort; // 2 bytes
????? Public int Myint; // 4 bytes
????? Public long mylong; // 8 bytes
}
Struct mystruct2
{
????? Public short myshort; // 2 bytes
????? Public int Myint; // 4 bytes
????? Public long mylong; // 8 bytes ????
????? Public byte mybyte; // 1 byte
}
[Structlayout (layoutkind. explicit)]
Struct myunion
{
????? [Fieldoffset (0)]
????? Public byte mybyte; // byte starting from zero
????? [Fieldoffset (0)]
????? Public short myshort; // The short from the zero position
????? [Fieldoffset (0)]
????? Public int Myint; // int starting from zero
????? [Fieldoffset (0)]
????? Public long mylong; // long from the zero position
}
Class Test
{
????? Public unsafe static void main ()
????? {
????????? Console. writeline ("sizeof (mystruct1): {0}", sizeof (mystruct1 ));
????????? Console. writeline ("sizeof (mystruct2): {0}", sizeof (mystruct2 ));
????????? Console. writeline ("sizeof (myunion): {0}", sizeof (myunion ));
?????}
}

Program output:
Sizeof (mystruct1): 16
Sizeof (mystruct2): 24
Sizeof (myunion): 8
??????? We can see that for all domain variables with the same unmanaged custom structure mystruct1 and mystruct2, just because we put the declared location of the mybyte domain in different places, their sizeof return values are different. Myunion structure because we use the structlayout feature to specify the storage layout of its domain members, its sizeof return value is the same as the return value of the domain variable mylong, which occupies the longest position, this is consistent with its behavior as a "Union.

Memory Allocation
??????? C # There is no memory Dynamic Allocation syntax (allocated to the stack) like C/C ++, and only stack allocation statements for partial unmanaged variables are provided: stackalloc unmanaged-type [expression], where expression is an integer expression or constant. Stack allocation space does not need to be cleared by ourselves, and is automatically reclaimed after the function exits. See the following example:

Using system;
Class Test
{
????? Unsafe static string inttostring (INT value)
????? {
????????? Char * buffer = stackalloc char [16];
????????? Char * P = buffer + 16;
????????? Int n = value> = 0? Value:-value;
????????? Do
????????? {
?????????????? * (-- P) = (char) (N % 10 + '0 ');
?????????????? N/= 10;
?????????} While (n! = 0 );

????????? If (value ????????? Return new string (p, 0, (INT) (buffer + 16-p ));
?????}

????? Public static void main ()
????? {
????????? Console. writeline (inttostring (12345 ));
????????? Console. writeline (inttostring (-999 ));
?????}
}

The inttostring function converts Integers to strings. A buffer character array is allocated to temporarily store converted character variables. If the system memory is insufficient, the stack allocation statement will throw the system. stackoverflowexception exception. This can be captured using the try statement. It is worth noting that C # specifies that stack allocation statements cannot be placed in catch or finally statement blocks.
??????? C # The Dynamic Allocation syntax is not provided, but what should we do if necessary? The answer is to call the dynamic allocation service of a specific platform by introducing external methods. See the following example:

Using system. runtime. interopservices;
Using system;
Public unsafe class memory
{
????? Static int pH = getprocessheap (); // obtain the process heap handle
????? Private memory (){}
????? Public static void * alloc (INT size) // Memory Allocation
????? {
????????? Void * result = heapalloc (pH, heap_zero_memory, size );
????????? If (result = NULL) throw new outofmemoryexception ();
????????? Return result;
?????}
????? Public static void free (void * block) // memory release
????? {
????????? If (! Heapfree (pH, 0, block) throw new invalidoperationexception ();
?????}

????? Const int heap_zero_memory = 0x00000008; // memory start address
????? [Dllimport ("Kernel32")]
????? Static extern int getprocessheap ();
????? [Dllimport ("Kernel32")]
????? Static extern void * heapalloc (INT hheap, int flags, int size );
????? [Dllimport ("Kernel32")]
????? Static extern bool heapfree (INT hheap, int flags, void * block );
}
Class Test
{
????? Unsafe static void main ()
????? {
????????? Byte * buffer = (byte *) memory. alloc (256 );
????????? For (INT I = 0; I ?????????????? Buffer [I] = (byte) I;
????????? For (INT I = 0; I ?????????????? Console. writeline (buffer [I]);
????????? Memory. Free (buffer );
?????}
}

We call getprocessheap, heapalloc, and heapfree in the kernel32.dll library on the Win32 platform to implement the dynamic memory allocation and release functions of the memory class. note that the memory is dynamically allocated on the heap. We must release it ourselves!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.