¿Por qué las direcciones de argc y argv están separadas por 12 bytes?

He ejecutado el siguiente programa en mi ordenador (Intel de 64 bits con Linux).

#include <stdio.h>

void test(int argc, char **argv) {
    printf("[test] Argc Pointer: %p\n", &argc);
    printf("[test] Argv Puntero: %p\n", &argv);
}

int main(int argc, char **argv) {
    printf("Puntero Argc: %p\n", &argc);
    printf("Argv Puntero: %p\n", &argv);
    printf("Tamaño de &argc: %lu\n", sizeof (&argc));
    printf("Tamaño de &argv: %lu\n", sizeof (&argv));
    test(argc, argv);
    retorna 0;
}

La salida del programa era

lenguaje: ninguno -->

$ gcc size.c -o size
$ ./size
Puntero Argc: 0x7fffd7000e4c
Argv Puntero: 0x7fffd7000e40
Tamaño de &argc: 8
Tamaño de &argv: 8
[test] Puntero Argc: 0x7fffd7000e2c
[test] Puntero Argv: 0x7fffd7000e20

El tamaño del puntero &argv es de 8 bytes. Esperaba que la dirección de argc fuera address of (argv) + sizeof (argv) = 0x7ffed1a4c9f0 + 0x8 = 0x7ffed1a4c9f8 pero hay un relleno de 4 bytes entre ellos. ¿Por qué ocurre esto?

Supongo que podría ser debido a la alineación de la memoria, pero no estoy seguro.

También noto el mismo comportamiento con las funciones que llamo.

Comentarios sobre la pregunta (6)
Solución

En su sistema, los primeros argumentos enteros o punteros se pasan en registros y no tienen direcciones. Cuando tomas sus direcciones con &argc o &argv, el compilador tiene que fabricar las direcciones escribiendo el contenido de los registros en las ubicaciones de la pila y dándote las direcciones de esas ubicaciones de la pila. Al hacer esto, el compilador elige, en cierto sentido, cualquier ubicación de pila que le resulte conveniente.

Comentarios (1)

¿Por qué las direcciones de argc y argv están separadas por 12 bytes?

Desde la perspectiva del estándar del lenguaje, la respuesta es "ninguna razón en particular". C no especifica ni implica ninguna relación entre las direcciones de los parámetros de las funciones. @EricPostpischil describe lo que probablemente ocurre en tu implementación particular, pero esos detalles serían diferentes para una implementación en la que todos los argumentos se pasen por la pila, y esa no es la única alternativa.

Además, me cuesta pensar en una forma en la que esa información pueda ser útil dentro de un programa. Por ejemplo, incluso si usted "sabe" que la dirección de argv es 12 bytes antes de la dirección de argc, todavía no hay una forma definida de calcular uno de esos punteros a partir del otro.

Comentarios (19)