Dirección del arreglo: diferencia entre tener un “y” y “no”

Tengo una estructura que se parece a esto:

struct packet { int a; char data[500]; }; typedef struct packet packet_t; 

Estoy un poco confundido por qué el siguiente código genera la misma dirección para cada printf:

 void myfunction() { packet_t packet; printf("%p\n", packet.data); //eg, outputs 0x7fff1c323c9c printf("%p\n", &packet.data); //eg, outputs 0x7fff1c323c9c } 

¿Alguien tiene una buena explicación para esto?

No sé por qué esto fue rechazado, es una buena pregunta que expone un comportamiento confuso de C.

La confusión viene porque normalmente cuando se define una matriz se crea un puntero real:

 char data[100]; printf("%p\n", data); // print a pointer to the first element of data[] printf("%p\n", &data); // print a pointer to a pointer to the first element of data[] 

Por lo tanto, en un sistema de escritorio de 32 bits típico, se asignan 4 bytes para los data , que es un puntero a 100 caracteres. Data , el puntero, existe en algún lugar en la memoria.

Al crear una matriz en una estructura, no se asigna ningún puntero. En su lugar, el comstackdor convierte las referencias a packet.data en un puntero en tiempo de ejecución, pero no asigna ninguna memoria para almacenarlo. Más bien, solo usa &packet + offsetof(data) .

Personalmente, preferiría que la syntax fuera consistente y requiriera un signo, con packet.data generando algún tipo de error de tiempo de comstackción.

En la mayoría de los casos, una expresión que tenga el tipo “matriz de elementos N de T ” se convertirá en una expresión de tipo “puntero a T “, y su valor será la dirección del primer elemento de la matriz. Esto es lo que sucede en la primera llamada a printf ; la expresión packet.data , que tiene el tipo char [500] , se reemplaza por una expresión del tipo char * , y su valor es la dirección del primer elemento, por lo que está imprimiendo efectivamente &packet.data[0] .

Una excepción a esta regla ocurre cuando la expresión de matriz es un operando del operador unario & ; el tipo de expresión &packet.data es char (*)[500] (puntero a la matriz de 500 elementos de char ).

La dirección de una matriz es la misma que la del primer elemento, por lo que ambas llamadas a printf muestran el mismo valor ; es solo que los tipos de expresiones son diferentes. Para ser pedante, ambas expresiones deben convertirse en void * en las llamadas a printf (el especificador de conversión %p espera un argumento void * ):

 printf("%p\n", (void *) packet.data); printf("%p\n", (void *) &packet.data); 

Eso es porque la matriz se desintegra a un puntero que apunta al primer elemento de la secuencia. Por lo tanto, la ubicación de la dirección de packet.data es la misma que &packet.data o &packet.data[0] .

Porque es lo único que se puede hacer además de que & packet.data cause un error de comstackción. El número entero a y el conjunto de caracteres de datos se presentan de forma secuencial en la stack, no se trata de una anulación de referencia.