2011-06-25 13 views
6

En código no seguro en C# Asigné puntero a la variable controlada de tipo matriz:declaración fijo en C# y logró puntero en código IL

int[] array = new int[3]; 
... 
fixed (int* ptr = array) 
{ 
    //some code 
} 

Entonces miré correspondiente parte del código IL:

.locals init ([0] int32[] 'array', 
     [1] int32& pinned ptr) 

y me pregunto, ya que se trata de código no seguro, y es int* ptr declaración de puntero no administrado (o eso creo por el momento), ¿por qué en el código IL no escribe int32* ptr, en lugar de int32& ptr?

Respuesta

3

http://www.ecma-international.org/publications/standards/Ecma-335.htm

Página 334

"1.1.5.2 punteros gestionados (tipo &)

1.2 punteros gestionados (&) puede apuntar a una variable local, un argumento, un método campo de un objeto, un campo de un tipo de valor , un elemento de una matriz, un campo estático , o la dirección donde un elemento justo después del final de una matriz sería almacenado (para índices de punteros en matrices administradas). Los punteros administrados no pueden ser nulos. (Serán reportados al recolector de basura, aunque no apuntan a logrado memoria)"

Página 149

7.1.2 clavado

La firma de codificación pinned debe aparecer solo en las firmas que describen las variables locales (§15.4.1.3). Mientras se está ejecutando un método con una variable local anclada, el VES no reubicará el objeto al que se refiere el local. Es decir, Si la implementación de la CLI usa un recolector de basura que mueve objetos, el recolector no moverá los objetos a los que hace referencia una variable local anclada activa. [Justificación: si los punteros no administrados se utilizan para desreferenciar objetos gestionados, estos objetos se fijarán. Esto sucede, por ejemplo, cuando un objeto administrado se pasa a un método diseñado para operar con datos no administrados. fundamento final]

Estoy de acuerdo con Hans en cuanto a la racionalidad detrás de la elección del diseño del lenguaje msil.


Estas dos cosas son diferentes:

int[] arry = new int[5]; 

fixed (int* ptr = arry) 
{ 
    ... 
} 

vs

int* ptr = stackalloc int[5]; 

Si nos fijamos en la IL creado para la segunda, verá este (que creo es lo que está esperando):

.locals init ([0] int32* ptr) 

En la primera versión (su versión), señala una instancia de Sistema.Array (un tipo gestionado). En mi versión (usando stackalloc) estás señalando lo que creo que esperas señalar ... un bloque de memoria lo suficientemente grande para 5 ints.

+0

No entendí el razonamiento: "Si se utilizan punteros no administrados para desreferenciar objetos gestionados, estos objetos se fijarán". En el código anterior, la matriz está delimitada por una declaración fija y todavía estamos utilizando un puntero administrado. – vldmrrdjcc

+0

@Vlad; editado para aclarar – Steve

+0

@Steve Gracias por su tiempo. Puedo notar que en su ejemplo con stackalloc int [5] ocupamos memoria en la pila, no en el montón, como con la nueva int [5], por lo que ahora esto no está sujeto a la recolección de basura, y no necesitamos arreglos declaración, ya que el compilador de C# solo le permite asignar un puntero a una variable administrada en una instrucción fija. Entonces, cuando estoy asignando un puntero a una variable administrada en una declaración fija, ¿ese puntero siempre se declara como puntero administrado? Puedo aceptar eso :) – vldmrrdjcc

2

Ildasm fue escrito por un programador de C++ en Microsoft. Un lenguaje donde la diferencia entre punteros y referencias es un gran problema. Una referencia de C++ debajo del capó también es un puntero, pero uno que nunca será nulo. Una referencia se identifica sintácticamente por &, un puntero es *.

Cuál es el caso aquí, hay una diferencia entre el puntero y el valor señalado. El valor apuntado puede ser nulo, pero la referencia al puntero nunca es nula. Se garantiza que la variable "array" está presente en el marco de la pila y, por lo tanto, su referencia tiene un valor no nulo. Solo es el valor puede ser nulo. Lo que sucede cuando la matriz no se inicializa. Este nivel de direccionamiento indirecto hizo que los indicadores fueran impopulares y en gran parte ausentes en el lenguaje C#. Y CS101.

+0

Huh, no entendí: en CLR las referencias a objetos son una cosa, y el puntero administrado es el segundo, y los punteros no administrados son terceros. Por ejemplo, este código C# inseguro: int x; int * y; y = & x; Aquí, en el código IL, tendremos .locals init (int32 * y) tal como se esperaba, y puedo decir que como he declarado x, & & x nunca es nulo, y el valor de x puede ser nulo, pero no veo la conexión entre ese hecho y la forma en que la variable local y se declara como puntero gestionado o no gestionado? – vldmrrdjcc

+0

@Vlad, respondí esa pregunta en mi publicación con una edición. – Steve

-5

C# es un lenguaje codificado administrado por lo que no habrá ningún puntero. pero hay una clase contenedora para utilizar los punteros que pueden ser debido a que notará alguna diferencia en estos dos.