Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C-sharp language specification.2004.pdf
Скачиваний:
14
Добавлен:
23.08.2013
Размер:
2.55 Mб
Скачать

Chapter 25 Unsafe code

125. Unsafe code

2An implementation that does not support unsafe code is required to diagnose any usage of the keyword

3unsafe.

4The remainder of this clause, including all of its subclauses, is conditionally normative.

5[Note: The core C# language, as defined in the preceding clauses, differs notably from C and C++ in its

6omission of pointers as a data type. Instead, C# provides references and the ability to create objects that are

7managed by a garbage collector. This design, coupled with other features, makes C# a much safer language

8than C or C++. In the core C# language it is simply not possible to have an uninitialized variable, a

9“dangling” pointer, or an expression that indexes an array beyond its bounds. Whole categories of bugs that

10routinely plague C and C++ programs are thus eliminated.

11While practically every pointer type construct in C or C++ has a reference type counterpart in C#,

12nonetheless, there are situations where access to pointer types becomes a necessity. For example, interfacing

13with the underlying operating system, accessing a memory-mapped device, or implementing a time-critical

14algorithm might not be possible or practical without access to pointers. To address this need, C# provides the

15ability to write unsafe code.

16In unsafe code it is possible to declare and operate on pointers, to perform conversions between pointers and

17integral types, to take the address of variables, and so forth. In a sense, writing unsafe code is much like

18writing C code within a C# program.

19Unsafe code is in fact a “safe” feature from the perspective of both developers and users. Unsafe code shall

20be clearly marked with the modifier unsafe, so developers can’t possibly use unsafe features accidentally,

21and the execution engine works to ensure that unsafe code cannot be executed in an untrusted environment.

22end note]

2325.1 Unsafe contexts

24The unsafe features of C# are available only in unsafe contexts. An unsafe context is introduced by including

25an unsafe modifier in the declaration of a type or member, or by employing an unsafe-statement:

26A declaration of a class, struct, interface, or delegate can include an unsafe modifier, in which case, the

27extent of that type-declaration is considered an unsafe context. [Note: If the type-declaration is partial,

28only that part is an unsafe context. end note]

29A declaration of a field, method, property, event, indexer, operator, instance constructor, destructor, or

30static constructor can include an unsafe modifier, in which case, the entire textual extent of that

31member declaration is considered an unsafe context.

32An unsafe-statement enables the use of an unsafe context within a block. The entire textual extent of the

33associated block is considered an unsafe context.

34The associated grammar extensions are shown below. For brevity, ellipses (...) are used to represent

35productions that appear in preceding clauses.

36class-modifier:

37

...

38unsafe

39struct-modifier:

40

...

41

unsafe

379

C# LANGUAGE SPECIFICATION

1

interface-modifier:

2

...

3unsafe

4delegate-modifier:

5

...

6unsafe

7field-modifier:

8

...

9unsafe

10method-modifier:

11

...

12unsafe

13property-modifier:

14

...

15unsafe

16event-modifier:

17

...

18unsafe

19indexer-modifier:

20

...

21unsafe

22operator-modifier:

23

...

24unsafe

25constructor-modifier:

26

...

27unsafe

28destructor-declaration:

29

attributesopt externopt unsafeopt ~ identifier ( )

destructor-body

30

attributesopt unsafeopt externopt ~ identifier ( )

destructor-body

31

static-constructor-modifiers:

 

32

externopt unsafeopt static

 

33

unsafeopt externopt static

 

34

externopt static unsafeopt

 

35

unsafeopt static

externopt

 

36

static externopt

unsafeopt

 

37static unsafeopt externopt

38embedded-statement:

39

...

40

unsafe-statement

41 unsafe-statement:

42unsafe block

43[Example: In the following code

44public unsafe struct Node

45{

46

public

int Value;

47

public

Node* Left;

48public Node* Right;

49}

380

Chapter 25 Unsafe code

1the unsafe modifier specified in the struct declaration causes the entire textual extent of the struct

2declaration to become an unsafe context. Thus, it is possible to declare the Left and Right fields to be of a

3pointer type. The example above could also be written

4public struct Node

5{

6

public

int Value;

7

public

unsafe Node* Left;

8public unsafe Node* Right;

9}

10Here, the unsafe modifiers in the field declarations cause those declarations to be considered unsafe

11contexts. end example]

12Other than establishing an unsafe context, thus permitting the use of pointer types, the unsafe modifier has

13no effect on a type or a member. [Example: In the following code

14public class A

15{

16

public unsafe virtual void F() {

17

char* p;

18

19}

20}

21public class B: A

22{

23

public override void F() {

24

base.F();

25

26}

27}

28the unsafe modifier on the F method in A simply causes the textual extent of F to become an unsafe

29context in which the unsafe features of the language can be used. In the override of F in B, there is no need

30to re-specify the unsafe modifier—unless, of course, the F method in B itself needs access to unsafe

31features.

32The situation is slightly different when a pointer type is part of the method’s signature

33public unsafe class A

34{

35public virtual void F(char* p) {…}

36}

37public class B: A

38{

39public unsafe override void F(char* p) {…}

40}

41Here, because F’s signature includes a pointer type, it can only be written in an unsafe context. However, the

42unsafe context can be introduced by either making the entire class unsafe, as is the case in A, or by including

43an unsafe modifier in the method declaration, as is the case in B. end example]

44When the unsafe modifier is used on a partial type declaration (§17.1.4), only that particular part is

45considered an unsafe context.

4625.2 Pointer types

47In an unsafe context, a type (§11) can be a pointer-type as well as a value-type, a reference-type, or a type-

48parameter.

49type:

50

51

52

53

value-type reference-type type-parameter pointer-type

381

C# LANGUAGE SPECIFICATION

1A pointer-type is written as an unmanaged-type or the keyword void, followed by a * token:

2pointer-type:

3

unmanaged-type *

4void *

5unmanaged-type:

6

type

7The type specified before the * in a pointer type is called the referent type of the pointer type. It represents

8the type of the variable to which a value of the pointer type points.

9Unlike references (values of reference types), pointers are not tracked by the garbage collector—the garbage

10collector has no knowledge of pointers and the data to which they point. For this reason a pointer is not

11permitted to point to a reference or to a struct that contains references, and the referent type of a pointer shall

12be an unmanaged-type.

13An unmanaged-type is any type that isn’t a reference-type, a type-parameter, or a generic struct-type and

14contains no fields whose type is not an unmanaged-type. In other words, an unmanaged-type is one of the

15following:

16sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.

17Any enum-type.

18Any pointer-type.

19Any non-generic user-defined struct-type that contains fields of unmanaged-types only.

20[Note: Constructed types and type-parameters are never unmanaged-types. end note]

21The intuitive rule for mixing of pointers and references is that referents of references (objects) are permitted

22to contain pointers, but referents of pointers are not permitted to contain references.

23[Example: Some examples of pointer types are given in the table below:

24

Example

Description

 

 

byte*

Pointer to byte

 

 

char*

Pointer to char

 

 

int**

Pointer to pointer to int

 

 

int*[]

Single-dimensional array of pointers to int

 

 

void*

Pointer to unknown type

 

 

25

26end example]

27For a given implementation, all pointer types shall have the same size and representation.

28[Note: Unlike C and C++, when multiple pointers are declared in the same declaration, in C# the * is written

29along with the underlying type only, not as a prefix punctuator on each pointer name. For example:

30

int* pi, pj; // NOT as int *pi, *pj;

31end note]

32The value of a pointer having type T* represents the address of a variable of type T. The pointer indirection

33operator * (§25.5.1) can be used to access this variable. [Example: Given a variable P of type int*, the

34expression *P denotes the int variable found at the address contained in P. end example]

35Like an object reference, a pointer can be null. Applying the indirection operator to a null pointer results

36in implementation-defined behavior. A pointer with value null is represented by all-bits-zero.

382

Chapter 25 Unsafe code

1The void* type represents a pointer to an unknown type. Because the referent type is unknown, the

2indirection operator cannot be applied to a pointer of type void*, nor can any arithmetic be performed on

3such a pointer. However, a pointer of type void* can be cast to any other pointer type (and vice versa) and

4compared to values of other pointer types.

5Pointer types are a separate category of types. Unlike reference types and value types, pointer types do not

6inherit from object and no conversions exist between pointer types and object. In particular, boxing and

7unboxing (§11.3) are not supported for pointers. However, conversions are permitted between different

8pointer types and between pointer types and the integral types. This is described in §25.4.

9A pointer-type can be used as the type of a volatile field (§17.4.3).

10[Note: Although pointers can be passed as ref or out parameters, doing so can cause undefined behavior,

11since the pointer might well be set to point to a local variable which no longer exists when the called method

12returns, or the fixed object to which it used to point, is no longer fixed. For example:

13using System;

14class Test

15{

16

static int value = 20;

17

unsafe static void F(out int* pi1, ref int* pi2) {

18

int i = 10;

19

pi1 = &i;

20

fixed (int* pj = &value) {

21

// ...

22

pi2 = pj;

23

}

24

}

25

static void Main() {

26

int i = 10;

27

unsafe {

28

int* px1;

29

int* px2 = &i;

30

F(out px1, ref px2);

31

Console.WriteLine("*px1 = {0}, *px2 = {1}",

32

*px1, *px2); // undefined behavior

33

}

34}

35}

36end note]

37A method can return a value of some type, and that type can be a pointer. [Example: When given a pointer to

38a contiguous sequence of ints, that sequence's element count, and some other int value, the following

39method returns the address of that value in that sequence, if a match occurs; otherwise it returns null:

40unsafe static int* Find(int* pi, int size, int value) {

41

for (int i = 0; i < size; ++i) {

42

if (*pi == value) {

43

return pi;

44

}

45

++pi;

46

}

47return null;

48}

49end example]

50In an unsafe context, several constructs are available for operating on pointers:

51The unary * operator can be used to perform pointer indirection (§25.5.1).

52The -> operator can be used to access a member of a struct through a pointer (§25.5.2).

53The [] operator can be used to index a pointer (§25.5.3).

54The unary & operator can be used to obtain the address of a variable (§25.5.4).

383

Соседние файлы в предмете Электротехника