matrices consecutivas

Aug 26 2020

Tengo curiosidad acerca de una oración en el estándar C18:

Dos punteros se comparan iguales si y solo si ambos son punteros nulos, ambos son punteros al mismo objeto (incluido un puntero a un objeto y un subobjeto al principio) o función, ambos son punteros a uno más allá del último elemento de la misma matriz o uno es un puntero a uno más allá del final de un objeto de matriz y el otro es un puntero al inicio de un objeto de matriz diferente que sigue inmediatamente al primer objeto de matriz en el espacio de direcciones. § 6.5.9 6

¿Por qué el objeto que sigue a la matriz tiene que ser necesariamente otra matriz? ¿No podría ser simplemente un objeto del mismo tipo que el tipo base de matriz (como un intinmediatamente después de un int[])?

No es de extrañar que haya probado este código:

#include <stdio.h>

struct test { int arr[10]; int i; };

int main() {
    struct test t;
    int *p, *q;
    p = t.arr + 10;
    q = &t.i;
    if (p == q)
        printf("Equal pointers.");
    return 0;
}

Y produce punteros iguales. ¿Este comportamiento no está garantizado en absoluto, solo es una coincidencia definida por la implementación?

Respuestas

24 chux-ReinstateMonica Aug 26 2020 at 17:41

OP: ¿Por qué el objeto que sigue a la matriz tiene que ser necesariamente otra matriz?

No es asi. "... comienzo de una matriz diferente ..." es una simplificación. La siguiente especificación es:

A los efectos de estos operadores, un puntero a un objeto que no es un elemento de una matriz se comporta igual que un puntero al primer elemento de una matriz de longitud uno con el tipo del objeto como su tipo de elemento. C17dr § 6.5.9 7


OP: ¿No podría ser simplemente un objeto cuyo tipo era el mismo que el tipo base de matriz (como un intinmediatamente después de un int[])?

Sí.

8 th33lf Aug 26 2020 at 17:26

En primer lugar, especificar una matriz aquí no excluye/prohíbe un solo objeto. Un solo objeto en la memoria es indistinguible de una matriz de tamaño 1.

( Editar : lea esta respuesta para una cita del estándar que establece esto explícitamente cuando se refiere a punteros)

En segundo lugar, la norma también trata de aclarar la declaración que ha citado, con la siguiente nota al pie que indica los escenarios en los que se aplica la regla:

Dos objetos pueden ser adyacentes en la memoria porque son elementos adyacentes de una matriz más grande o miembros adyacentes de una estructura sin relleno entre ellos, o porque la implementación eligió colocarlos así, aunque no estén relacionados.

Poniéndolo todo junto, lo que el estándar intenta decir aquí es que, en general, dos punteros a objetos diferentes no deben compararse iguales. Sin embargo, dado que es legal apuntar uno más allá de un objeto de matriz en la memoria, si resulta que hay un objeto (matriz) diferente en esa ubicación, aún es legal que dicho puntero se compare igual a un puntero al objeto adyacente. Ahora, puede haber o no un objeto válido en esta ubicación, debido a las opciones de alineación y el relleno, pero si hay uno, es aceptable que estos punteros se comparen como iguales.

En su ejemplo, si cambié la matriz a un carácter, los punteros probablemente se compararían de manera desigual porque el compilador elegiría alinear el int a 4 bytes (en la mayoría de las plataformas de 32 o 64 bits), introduciendo así el relleno. Este comportamiento sigue siendo legal según la norma.

#include <stdio.h>

struct test { char arr[10]; int i; };

int main() {
    struct test t;
    int *p, *q;
    p = (int*)(t.arr + 10);
    q = &t.i;
    if(p == q)
      printf("Equal pointers.");
    else
      printf("Unequal pointers.");
    return 0;
}