Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / Premier Press - C# Professional Projects

.pdf
Скачиваний:
475
Добавлен:
12.02.2016
Размер:
14.7 Mб
Скачать

This page intentionally left blank

 

 

Y

 

L

 

F

 

M

 

A

 

E

 

T

 

 

Team-Fly®

PART X

Appendixes

This page intentionally left blank

Appendix A

Unsafe Code

832

Part X

APPENDIXES

 

 

 

In this chapter, you will learn about the basics of pointers. You will learn to declare and implement pointers. In addition, you will learn about using point-

ers with managed code. Finally, you will learn to compile unsafe code.

Pointers

Pointers are not a new concept for C and C++ programmers. A pointer is a variable similar to a reference and points to an address in memory. A pointer stores the actual memory address and makes it available to you.

Pointers are extensively used in C and C++ for dynamic allocation of memory and to directly access the memory. However, if pointers are not used properly, they may lead to memory corruption. To avoid such situations, C# hides most of the memory management operations from the end user. However, there may be cases where you need to have direct access to memory. C# allows you to use pointers in such cases.The following list contains some of the cases where you need to access memory addresses by using pointers.

You may be required to use pointers when you are working with existing code written in C or C++ that uses pointers.

You may require pointers to create applications with high performance requirements.

Pointers allow you to work with the underlying operating system by providing an interface between the program code and the operating system.

When you are debugging an application, you may be required to have direct access to a particular memory location. In addition to various debugging options provided by Visual Studio .NET, pointers help you in this case by allowing you to access the data stored at the specified memory location.

Pointers also provide you with an interface to work with advanced COM (Component Object Model ) applications containing structures that use pointers.

UNSAFE CODE Appendix A 833

As discussed earlier, if pointers are not used effectively, they can be a problem to programmers. The following list contains some of the problems faced by programmers while using pointers.

Working with pointers requires extensive and high-level programming. If you are not careful while programming with pointers, you may introduce errors in your code, which may even result in the program crashing.

When a pointer is no longer used by any program, you need to deallocate its memory. If you forget to deallocate the memory associated with the pointer, it may lead to unpredictable problems in your code. Debugging these problems can be time-consuming and tedious.

Pointers make the address of a memory location transparent to the users. Therefore, it becomes possible for users to manipulate the memory addresses. This may introduce errors in your code by making it unsafe to use.

While writing a program that uses pointers, you may make your pointer point to a wrong memory location. Therefore, when your program code accesses an incorrect memory location, it may produce errors or may even result in the program crashing.

The major problem with using pointers in the program code used to be because of the garbage collection system of CLR (common language runtime). The garbage collection system operates in the background to deallocate memory to objects that are no longer used by any program. The garbage collection system also causes the movement of objects within memory. Each time an object is moved, C# updates its reference. However, there is no mechanism by which the programmer is informed about the new memory location of the object. This may cause your pointer to point to a different memory location, thereby introducing errors in the program. As a solution to this problem, the .NET Framework introduced the concept of unsafe code. You will learn about unsafe code later in this appendix.

In spite of these problems, programmers have been extensively using pointers in C and C++. This is mainly because pointers offer several advantages to programmers, thereby helping them to write complex applications. Some of the advantages of using pointers in your code include backward compatibility with code

834

Part X

APPENDIXES

 

 

 

written in C and C++. Pointers also help you to access and manipulate data easily and efficiently, thereby increasing the performance of your application.

Because of the advantages of pointers, C# has retained pointers in some capacity. However, to prevent memory corruption in C#, pointers are used only within blocks of code for which the pointer is required.This restricts the programmer to using pointers only when they are required and marked. You can use the unsafe keyword to mark the block of code in which you need to declare a pointer. A class, method, struct, constructor, or block of code within a method can be marked as unsafe. However, you cannot mark a static constructor as unsafe.

When you mark code as unsafe, you inform the compiler that the program is not sure whether the code is safe to execute. Therefore, to execute code marked as unsafe, you need to give full trust to the program code. As discussed earlier, the major problem that you face while working with pointers is because of the garbage collection system of CLR. Therefore, to solve this problem, C# runs the code marked as unsafe outside the garbage collection system. This allows you to perform memory management processes directly. Therefore, you can only declare a pointer in the set of statements marked as unsafe.

Declaring Pointers

The following syntax shows how to declare a pointer. An asterisk (*) is used to declare a pointer.

unsafe class Class1

{

int *pointer1;

}

The preceding code marks the class Class1 as unsafe.The pointer named pointer1 is declared in this class. You can also mark a variable as unsafe. However, you can only do this in the block of code that is marked unsafe. After you mark code as unsafe, you need to inform the compiler that your program contains unsafe code. This will allow you to declare pointers in the unsafe code.To inform the compiler about the presence of unsafe code, you use the flag unsafe with the compile command. You will learn about the compilation of unsafe code later in this appendix.

C# allows you to declare more than one pointer of the same data type in a single command. In this case, you will use only one asterisk sign, although in C++, you

UNSAFE CODE Appendix A 835

were required to have different asterisk for each pointer declaration. It is an exception in the syntax of a pointer declaration statement.

int *pointer1, pointer2;

This code will give an error in C++. To declare two pointers in C++, you use the following syntax:

int *pointer1, *pointer2;

After a pointer is declared, you can use it like any other variable used in the code. However, to use a pointer, you need to initialize the pointer with the address in the memory. Similar to variables, you cannot use a pointer without initializing it. A pointer can also be initialized to a null value.

After initializing a pointer, you can use it with any program code. All programs in C# are classified as managed or unmanaged code. The following section discusses the types of code in detail.

Types of Code

The code in C# is classified as managed or unmanaged code based on the level of control that CLR has over the code.

Managed Code

Managed code contains some information about the code. This information contained in managed code is called metadata. Managed code in the .NET Framework is controlled by CLR , which uses metadata to provide safe execution of the program code. CLR also helps in memory management, security, and interoperability of the code with other languages. In addition to providing safe execution of the program, managed code aims at targeting the CLR services. These CLR services include locating and loading classes and interoperating with the existing DLL (dynamic link librar y) code and COM objects. By default, all code in C# is managed code.

Unmanaged Code

Code that is marked with the unsafe keyword is called unmanaged code. The unmanaged code does not provide any information about the code. In other

836

Part X

APPENDIXES

 

 

 

words, unmanaged code does not provide CLR with metadata. CLR is not sure of the safe execution of unmanaged code, and therefore, unmanaged code is considered to be unsafe. You can only run unsafe code in a fully trusted environment. Because of the problems that you face while working with pointers, C# allows you to use pointers in unsafe code.

After declaring a pointer in unsafe code, you need to implement pointers.

Implementing Pointers

A pointer that you declare must be of the type pointer. You can declare a pointer type by using the asterisk (*) sign after the void keyword or by declaring the pointer as an unmanaged-type. For example:

void *

or

unmanaged-type *

In the preceding syntax, void is the data type of the variable to which the pointer points. This data type is called the reference type. However, an unmanaged-type can be of any data type other than the reference type. The unmanaged-type data types

include all variable types, enum, pointer, or struct.

While working with pointer types, you need to remember the following guidelines:

The void type pointer points to any variable type that is not known to the user. Therefore, you cannot use the indirection operator with the void type pointer. In addition, you cannot perform any arithmetic operation on the void pointer. However, you can type cast the void pointer to any other pointer type and vice versa. You will learn about the indirection operator and pointer arithmetic later in this appendix.

Because pointers are of unmanaged-type, they are not managed by garbage

collector. Therefore, you cannot declare a pointer pointing to a reference

type.

C# does not allow a pointer to inherit from an object. In addition, you cannot type cast a pointer type to an object and vice versa. This implies that you can neither box nor unbox a pointer. However, if you convert a pointer to a value type, you can box this value type variable.

UNSAFE CODE Appendix A 837

As you have seen, pointers are used with unmanaged code. However, in some cases, C# also allows you to use pointers with managed code. The following section discusses the use of pointers with managed code in detail.

Using Pointers with Managed Code

The main problem of using pointers with managed code is that the garbage collection system of CLR controls the execution of the managed code. The garbage collection system moves the objects internally in the memor y. If you use pointers in managed code, the garbage collector does not automatically change the address stored in the pointer. This is because the garbage collector does not have control over pointers. This may cause problems with your code, as the pointer points to incorrect memory locations.

To sol ve this problem, C# allows you to prevent CLR from moving a specified object in the memory. To do this, you use the fixed statement. To understand the fixed statement, look at its syntax.

fixed (pointer declaration statement)

Here, the fixed keyword is used to pin the position of the managed object. The pointer declaration statement declares and initializes a pointer with the address of the managed object. Until the C# compiler finishes the compilation of the program code, the garbage collection system is not allowed to move the object that is marked with the fixed keyword.

Having seen the use of pointers in managed and unmanaged code, you will learn about the operators that you can use to work with pointers.

Working with Pointers

In addition to the operators used with variables, C# supports some more operators to be used with pointers.

indirection operator. The indirection operator is used to retrieve the content stored at the memory address referred by the pointer. In other words, the indirection operator converts a pointer to a variable of the value type. You can convert a pointer to almost every variable data type or a struct. However, you cannot convert a pointer to a class or an array. This operator is denoted by an asterisk (*) sign, and it is also called a

dereference operator.