Estaba leyendo algo de código y se encontró que la persona estaba usando arr[-2] para acceder a la 2ª elemento antes de la arr, así:

|a|b|c|d|e|f|g|
       ^------------ arr[0]
         ^---------- arr[1]
   ^---------------- arr[-2]

Es que se permite?

Sé que arr[x] es el mismo que *(arr + x). Así arr[-2] es *(arr - 2), que parece OK. ¿Qué te parece?

InformationsquelleAutor bodacydo | 2010-08-13

7 Comentarios

  1. 156

    Que es correcto. De C99 §6.5.2.1/2:

    La definición de la subíndice
    operador [] es que E1[E2] es
    idéntica a (*((E1)+(E2))).

    No hay magia. Es un 1-1 de equivalencia. Como siempre cuando desreferenciar un puntero (*), usted necesita para asegurarse de que está apuntando a una dirección válida.

    • Tenga en cuenta también que usted no tiene que eliminar la referencia del puntero para obtener la UB. Simplemente computación somearray-2 es indefinido, a menos que el resultado está en el intervalo desde el inicio de somearray a 1 más allá de su final.
    • En los libros antiguos de la [] se hace referencia como un la sintaxis de azúcar para la aritmética de punteros. Favoritos manera de confundir a los principiantes es escribir 1[arr] – en lugar de arr[1] – y verlos adivinar lo que se supone que significa eso.
    • Lo que sucede en los sistemas de 64 bits (LP64) cuando usted tiene una versión de 32 bits int índice que es negativo ? Si el índice de ascender a una de 64 bit signed int antes la dirección de cálculo ?
    • §6.5.6/8 (operadores Aditivos), «Cuando una expresión que tiene el tipo integer es añadido o sustraído de un puntero, el resultado tiene el tipo del puntero operando. Si el puntero operando apunta a un elemento de un array de objetos, y la matriz es suficientemente grande, el resultado apunta a un elemento de desplazamiento del elemento original que hace que la diferencia de los subíndices de la resultante y el original de los elementos de la matriz es igual a la expresión de tipo entero.» Así que creo que va a ser promovido, y ((E1)+(E2)) será de un (64-bit) puntero con el valor esperado.
    • gracias por que – suena como que debe el trabajo como uno podría esperar.
    • De un lado curioso comentario: Dado que el operador de subíndice [] está definido de tal manera que E1[E2] es idéntica a la (*((E1)+(E2))) (véase la respuesta por Mateo Flaschen), es realmente válido el código C para escribir 2[arr] en lugar de arr[2]. Tengo que admitir que esta es deliberadamente ofuscación de código, sin embargo.

  2. 62

    Esto sólo es válido si arr es un puntero que apunta a que el segundo elemento de una matriz o más tarde elemento. De lo contrario no es válido, porque usted podría tener acceso a memoria fuera de los límites de la matriz. Así, por ejemplo, sería incorrecto:

    int arr[10];
    
    int x = arr[-2]; //invalid; out of range

    Pero estaría bien:

    int arr[10];
    int* p = &arr[2];
    
    int x = p[-2]; //valid:  accesses arr[0]

    Es, sin embargo, inusual para el uso de un signo negativo.

    • Yo no iría tan lejos como para decir que no es válido, sólo potencialmente complicado
    • El código en el primer ejemplo genera un comportamiento indefinido.
    • BSTR es un buen ejemplo en windows. Cualquier asignador de depuración. Nada de malo con ello.
    • No es válido. El estándar de C, explícitamente tiene un comportamiento indefinido. Por otro lado, si int arr[10]; eran parte de una estructura con otros elementos antes, arr[-2] potencialmente podría estar bien definidos, y que podría determinar si es basado en el offsetof, etc.
    • BSTR y depuración asignadores de ambos asignar espacio y devuelve un puntero en algún lugar dentro de ese espacio. Esta propiedad hace que un desfase negativo «seguro» para algunos valores de «seguro». El ejemplo de James da aquí de arr[-2] es explícitamente un comportamiento indefinido porque los intentos de acceso a un lugar antes del comienzo de arr sí mismo. Tenga en cuenta que incluso la informática arr-2 sin necesidad de acceder a la ubicación es un comportamiento indefinido.
    • +1 por señalar un comportamiento indefinido
    • Niza ejemplos. Por cierto, me pregunto si este problema ha sido abordado en K&R de la Biblia (El Lenguaje de Programación C, 2ª Edición)? Si sí, en qué sección?
    • No sé. Ha sido un largo tiempo desde que abrí mi copia de K&R y hago muy poco de programación en C.
    • La encontró en la K&R la Sección 5.3, cerca del final: If one is sure that the elements exist, it is also possible to index backwards in an array; p[-1], p[-2], and so on are syntactically legal, and refer to the elements that immediately precede p[0]. Of course, it is illegal to refer to objects that are not within the array bounds. aun así, el ejemplo es el mejor en el que me ayude a entender esto. Gracias!
    • También pensé en negativo indicies de que explícitamente está definido para provocar un comportamiento indefinido. Ahora he tratado de encontrar una prueba en la norma y que no. Puede que me apunte a ella?
    • operador [] se define en términos de + y unario * operadores. Negativo índice ha definido el comportamiento de la fib el desplazamiento se define por +.
    • Lo siento por el hilo de la nigromancia, pero me encanta cómo K&R son ambiguos en cuanto a lo «ilegal» significa. La última frase la hace sonar como si fuera de los límites de los accesos de tirar un error de compilación. Ese libro es un veneno para los principiantes.

  3. 10

    Suena bien para mí. Sería un raro caso de que usted podría legítimamente necesita sin embargo.

    • No que raro – es muy útil, por ejemplo, en el procesamiento de la imagen con los vecinos, a los operadores.
  4. 7

    Lo que, probablemente, fue que arr estaba apuntando al centro de la matriz, por lo tanto, haciendo arr[-2] señalando algo en la matriz original sin salir de los límites.

  5. 7

    No estoy seguro de qué tan confiable es esto, pero acabo de leer la siguiente advertencia acerca de la negativa de la matriz de índices en sistemas de 64 bits (LP64 presumiblemente): http://www.devx.com/tips/Tip/41349

    El autor parece estar diciendo que el 32 bits int matriz de índices con 64 bits de direccionamiento puede resultar en la mala dirección de los cálculos a menos que el índice de la matriz se promueve explícitamente a 64 bits (por ejemplo, a través de un argumento de fundición). En realidad he visto un error de su naturaleza con la versión PowerPC de gcc 4.1.0, pero no sé si es un bug del compilador (es decir, debe trabajar según el estándar C99), o corregir el comportamiento (es decir, el índice de necesidades de un molde para 64 bits para un correcto comportamiento) ?

    • Esto suena como un error en el compilador.
  6. 1

    Sé que la pregunta es contestada, pero no pude resistir a compartir esta explicación.

    Recuerdo Principios de Compilador de diseño,
    Supongamos que a es una matriz int y el tamaño de int es de 2,
    & dirección Base de una es de 1000.

    Cómo a[5] funcionará ->

    Base Address of your Array a + (index of array *size of(data type for array a))
    Base Address of your Array a + (5*size of(data type for array a))
    i.e. 1000 + (5*2) = 1010

    Esta explicación es también la razón por la negativa de los índices de las matrices de trabajo en la C.

    es decir, si puedo acceder a a[-5] me va a dar

    Base Address of your Array a + (index of array *size of(data type for array a))
    Base Address of your Array a + (-5 * size of(data type for array a))
    i.e. 1000 + (-5*2) = 990

    Volverá a mí objeto en la ubicación 990.
    Por esta lógica podemos acceder a índices negativos en la Matriz en C.

  7. 1

    Acerca de por qué alguien desea utilizar índices negativos, las he usado en dos contextos:

    1. Tener una tabla de combinatoria de números que indica peine[1][-1] = 0; usted siempre puede comprobar los índices antes de acceder a la tabla, pero de esta manera el código es más limpio y se ejecuta más rápido.

    2. Poner un centinel en el comienzo de una tabla. Por ejemplo, usted quiere usar algo como

       while (x < a[i]) i--;

    pero, a continuación, usted debe también comprobar que i es positivo.

    Solución: hacer que a[-1] es -DBLE_MAX, por lo que x&lt;a[-1] siempre será falsa.

Dejar respuesta

Please enter your comment!
Please enter your name here