2009-05-25 12 views

Respuesta

24

El compilador dará vuelta

index[array] 

en

*(index + array) 

con la sintaxis normal, se convertiría

array[index] 

en

*(array + index) 

y, por lo tanto, puede ver que ambas expresiones evalúan con el mismo valor. Esto es válido tanto para C como para C++.

+13

Esta ilustración de "transformación" solo se cumple cuando una de las variables es un puntero o una matriz y la otra es un tipo entero, es decir, el caso C habitual. En C++, a [b] pierde su simetría ya que el operador [] puede ser una función miembro sobrecargada y el compilador no puede usar * (a + b) en su lugar. * (a + b) podría tener un tipo diferente y un valor diferente o podría no ser una expresión válida en absoluto. –

+0

+1. Guay. Nunca lo pensé de esa manera. – ralphtheninja

+0

@Charles: ¡buen punto! –

6

Desde los primeros días de C, la expresión a[i] era simplemente la dirección de un [0] agregado a i (ampliado por el tamaño de un [0]) y luego se le quita la referencia. De hecho, todos estos fueron equivalentes:

a[i] 
i[a] 
*(a+i) 

====

Lo único que estaría preocupa es el actual desindexación. Si bien todas producen la misma dirección , la eliminación de referencias puede ser una preocupación si los tipos de a y i son diferentes.

Por ejemplo:

int i = 4; 
    long a[9]; 
    long x = a[i]; //get the long at memory location X. 
    long x = i[a]; //get the int at memory location X? 

no he hecho probado que la conducta pero es algo que es posible que desee tener en cuenta. Si cambia lo que se desreferencia, es probable que cause todo tipo de problemas con las matrices de objetos también.

====

Actualización:

es probable que pueda ignorar el poco por encima entre las líneas =====. Lo he probado bajo Cygwin con un corto y un largo y parece estar bien, así que creo que mis temores eran infundados, al menos para los casos básicos. Todavía no tengo idea de qué pasa con los más complicados porque no es algo que probablemente quiera hacer.

+0

¿Cómo es diferente hoy? – Ben

+2

No creo que sea diferente. Quise decir que data de los primeros días, aunque no era solo así en los primeros días. – paxdiablo

+0

Esto está mal. De cualquier forma, el compilador sabe agregar un int a un resultado largo * (en cualquier orden) en un largo *, que luego se desreferencia a largo. Y esto se aplica a cualquier tipo de puntero, incluido el definido por el usuario. –

5

Como Matthew Wilson discute en Imperfect C++, esto puede ser utilizado para hacer cumplir la seguridad de tipos en C++, mediante la prevención de uso de DIMENSION_OF() -como macros con instancias de tipos que definen el operador subíndice, como en:

#define DIMENSION_OF_UNSAFE(x) (sizeof(x)/sizeof((x)[0])) 

#define DIMENSION_OF_SAFER(x) (sizeof(x)/sizeof(0[(x)])) 

int ints[4]; 

DIMENSION_OF_UNSAFE(ints); // 4 
DIMENSION_OF_SAFER(ints); // 4 

std::vector v(4); 

DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong 
DIMENSION_OF_SAFER(v); // does not compile 

Hay más en esto, para tratar con punteros, pero eso requiere un poco de inteligencia de plantilla adicional. Consulte la implementación de STLSOFT_NUM_ELEMENTS() en las bibliotecas STLSoft, y lea sobre esto en el capítulo 14 de Imperfect C++.

editar: algunos de los comentaristas sugieren que la implementación no rechaza los punteros. Lo hace (así como también los tipos definidos por el usuario), como se ilustra en el siguiente programa. Puede verificar esto mediante las líneas 16 y 18 sin comentario (solo hice esto en Mac/GCC4, y rechaza ambas formas).

1 
2 #include <stlsoft/stlsoft.h> 
3 
4 #include <vector> 
5 
6 #include <stdio.h> 
7 
8 int main() 
9 { 
10   int  ar[1]; 
11   int* p = ar; 
12   std::vector<int>  v(1); 
13 
14   printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar)); 
15 
16 //  printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p)); 
17 
18 //  printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v)); 
19 
20   return 0; 
21 } 
22 
+0

Se puede lograr una mejor implementación de 'dimensión' con plantillas: plantilla std :: size_t dimension (T [N] & x) {return N; }. Eso será más seguro que el tamaño de (a)/sizeof (a [0]) con matrices (que no se han deteriorado en punteros). –

+1

dribeas: el problema con eso es que ya no es una expresión en tiempo de compilación. La técnica descrita por Wilson ilustra una versión en tiempo de compilación. Como dije, está disponible en las bibliotecas de STLSoft. – dcw

+0

También hay una forma de obtener una expresión de tiempo de compilación: template char (& an_array (T (&) [N])) [N]; Eso evaluará una referencia a una matriz de caracteres con el mismo tamaño.Úselo como: int v [sizeof an_array (another_array)]; –

0

en C y C++ (con array ser un puntero o matriz) es una característica del lenguaje: puntero aritmética. La operación a [b] donde a o b es un puntero se convierte en aritmética de puntero: * (a + b). Además de ser simétrico, reordenar no cambia el significado.

Ahora, hay diferencias para los no punteros. De hecho, dado un tipo A con operador sobrecargado [], entonces un [4] es una llamada a método válida (llamará al operador A ::) pero el opuesto ni siquiera se compilará.