Representación visual de punteros y punteros a punteros..

Iniciado por digimikeh, 2 Mayo 2019, 17:48 PM

0 Miembros y 1 Visitante están viendo este tema.

RayR

La cuestión con los punteros a funciones es que depende del compilador, sistema operativo, etc. a dónde apunten. La respuesta obvia sería "a la dirección de la función", pero qué es exactamente eso o en dónde existe, depende de la implementación. Lo que sí podrías dar por hecho es que las funciones no viven ni en la pila ni en el heap. Típicamente las instrucciones ejecutables se colocan en un parte de la memoria conocida como el segmento de texto (a veces llamado segmento de código), que suele ser de sólo lectura.

digimikeh

Vale, entonces se aloja en una especie de registro...

Ya se han aclarado varias dudas
Gracias
Dungeons & dragons;
dragons.Attack();

Loretz

#12
En la línea:
int (* pSumar) (int)(int) = sumar;
hay un error, debería ser:
int (*pSumar) (int, int) = &sumar; // el & delante no es extrictamente necesario pero conviene


CitarVale, entonces se aloja en una especie de registro...
Tampoco.

Como te decía RayR, la dirección de una función (no de una "función miembro", recuerdas?) suele estar en memoria de sólo lectura (que en inglés la vas a encontrar como "code segment" o "text segment"). Entonces, un puntero a función va a apuntar a esa parte de la memoria que no es stack ni heap, sino la parte donde está el código del programa cuando se carga en memoria.

En algún momento también se mencionó que los "string literals" ("hola mundo" por ejemplo) también estaban en un sector especial de memoria de solo lectura, el "data segment", que tampo es stack ni heap.

Con respecto a la Call Stak, Hay un artículo en Wikipedia que vale la pena ser leído:
https://en.wikipedia.org/wiki/Call_stack

Por si no quedara del todo claro, no hay que perder de vista que cuando se habla de la "memoria" se trata de la "virtual address space". Creo que aquí encontrarás respuesta a las dudas que ni siquiera sabías que debías tener:
https://en.wikipedia.org/wiki/Virtual_address_space

[Nota]
También es cierto que estas representaciones corresponden a un modelo, el "C Abstract Machine Model" [http://web.stanford.edu/group/sequoia/cgi-bin/book/export/html/15], que es un modelo abstracto que los compiladores se encargan de trasladar a la máquina real.
Habitualmente los microprocesadores suelen tener niveles de memoria caché y evitan acceden directamente la disco o a la memoria RAM, y en un sistema suele haber más de un microprocesador con más de un "core" cada uno, y es frecuente que compartan los mismos datos, figúrate. Apropósito de esto, el C++ define su "memory model" https://en.cppreference.com/w/cpp/language/memory_model
[/Nota]

RayR

#13
Tal cual te lo explicó Loretz. Creo que yo te confundí cuando te dije que dependía. Pasa que C deja muchas cosas abiertas a que los compiladores las implementen como quieran, siempre que cumplan con ciertas condiciones. En el caso de los punteros a funciones, sé que al menos en algún compilador viejo de C, no apuntaban directamente a la dirección de la función, sino a una estructura rara y de ahí ya la localizaban. En realidad, con los compiladores/arquitecturas actuales, puedes estar bastante seguro de que apuntan a la dirección de la función en el segmento de código. Es sólo que el pedante que a veces habita en mí sale y dice: ¡no necesariamente!  :D. Eso sí, no olvides que esto se refiere a punteros a funciones; en el caso de funciones miembro, como dice Loretz, es algo muy diferente y depende totalmente de cada implementación.

Por cierto, los ejemplos que habías puesto al principio, donde los punteros estaban en la pila, son correctos siempre que los punteros sean variables locales no static. Las variables globales y las variables locales declaradas como static, (llamémoslas de forma general, variables de duración estática), se localizan en el segmento de datos. Para ser más específicos (dado que puede que leas sobre esto en otro lado y te puedas confundir), en el archivo compilado, las variables de duración estática inicializadas (ejemplo: static int n = 5;) se colocan en la sección data. Las variables de duración estática no inicializadas no se suelen almacenar en el archivo binario (dado que no tienen ningún valor específico, no tendría caso ocupar espacio) sino que se coloca su tamaño conjunto en una sección llamada bss. Cuando el programa se ejecuta, los datos inicializados se colocan en el segmento de datos (data segment). En cuanto a los no inicializados, se reserva la cantidad de espacio que bss especifica, y se inicializan a cero, también en el segmento data. Porque una vez que el programa está en ejecución ya no se suele hacer distinción entre data y bss: todo se encuentra en data.

Editado: no sé qué pasó que mi mensaje había quedado hecho un lío. En fin, en resumen, si los punteros fueran globales o locales static, se encontrarían en el segmento de datos. Los datos apuntados por ellos, naturalmente, no se verían afectados.