BREVE RESUMEN
(que también pondré en la parte superior):
(0) Pensar en los punteros como direcciones es a menudo una buena herramienta de aprendizaje, y a menudo es la implementación real de punteros a tipos de datos ordinarios.
(1) Pero en muchos, quizás la mayoría, los punteros de compiladores a funciones no son direcciones, sino que son más grandes que una dirección (normalmente 2x, a veces más), o en realidad son punteros a una estructura en la memoria que contiene las direcciones de función y cosas como Una piscina constante.
(2) Los punteros a los miembros de datos y los punteros a los métodos a menudo son aún más extraños.
(3) Código x86 heredado con problemas de puntero LEJOS y CERCA
(4) Varios ejemplos, especialmente el IBM AS / 400, con "punteros gordos" seguros.
Estoy seguro de que puedes encontrar más.
DETALLE:
UMMPPHHH !!!!! Muchas de las respuestas hasta ahora son respuestas típicas de "programador weenie", pero no compilador weenie o hardware weenie. Como pretendo ser un pito de hardware, y a menudo trabajo con pitos de compilación, permítanme agregar mis dos centavos:
En muchos, probablemente la mayoría de los compiladores de C, un puntero a datos de tipo T
es, de hecho, la dirección de T
.
Multa.
Pero, incluso en muchos de estos compiladores, ciertos punteros NO son direcciones. Puedes decir esto mirando sizeof(ThePointer)
.
Por ejemplo, los punteros a las funciones son a veces mucho más grandes que las direcciones normales. O pueden implicar un nivel de indirección. Este artículoproporciona una descripción, que involucra el procesador Intel Itanium, pero he visto otras. Por lo general, para llamar a una función debe conocer no solo la dirección del código de la función, sino también la dirección del grupo constante de la función, una región de la memoria desde la cual las constantes se cargan con una sola instrucción de carga, en lugar de que el compilador tenga que generar una constante de 64 bits de varias instrucciones de carga inmediata y cambio y OR. Entonces, en lugar de una sola dirección de 64 bits, necesita 2 direcciones de 64 bits. Algunas ABI (interfaces binarias de aplicación) mueven esto como 128 bits, mientras que otras usan un nivel de indirección, siendo el puntero de función la dirección de un descriptor de función que contiene las 2 direcciones reales que acabamos de mencionar. ¿Cual es mejor? Depende de su punto de vista: rendimiento, tamaño del código, y algunos problemas de compatibilidad: a menudo el código supone que un puntero puede convertirse en un largo o un largo largo, pero también puede suponer que el largo largo es exactamente 64 bits. Es posible que dicho código no cumpla con los estándares, pero, sin embargo, los clientes pueden querer que funcione.
Muchos de nosotros tenemos recuerdos dolorosos de la antigua arquitectura segmentada Intel x86, con PUNTOS CERCANOS y PUNTOS LEJOS. Afortunadamente, estos ya están casi extintos, así que solo un resumen rápido: en modo real de 16 bits, la dirección lineal real era
LinearAddress = SegmentRegister[SegNum].base << 4 + Offset
Mientras que en modo protegido, podría ser
LinearAddress = SegmentRegister[SegNum].base + offset
con la dirección resultante que se verifica contra un límite establecido en el segmento. Algunos programas no utilizaron declaraciones de puntero C / C ++ FAR y NEAR realmente estándar, pero muchos simplemente dijeron *T
--- pero había conmutadores de compilador y enlazador, por ejemplo, los punteros de código podrían estar cerca de punteros, solo un desplazamiento de 32 bits contra lo que haya en el registro CS (segmento de código), mientras que los punteros de datos pueden ser punteros FAR, que especifican tanto un número de segmento de 16 bits como un desplazamiento de 32 bits para un valor de 48 bits. Ahora, ambas cantidades están ciertamente relacionadas con la dirección, pero dado que no son del mismo tamaño, ¿cuál de ellas es la dirección? Además, los segmentos también tenían permisos (solo lectura, lectura-escritura, ejecutable) además de cosas relacionadas con la dirección real.
Un ejemplo más interesante, en mi humilde opinión, es (o tal vez fue) la familia IBM AS / 400. Esta computadora fue una de las primeras en implementar un sistema operativo en C ++. Los punteros en esta máquina eran típicamente 2 veces el tamaño real de la dirección, por ejemplo, como esta presentacióndice, punteros de 128 bits, pero las direcciones reales eran de 48-64 bits y, de nuevo, información adicional, lo que se llama una capacidad, que proporcionaba permisos como lectura, escritura, así como un límite para evitar el desbordamiento del búfer. Sí: puede hacerlo de manera compatible con C / C ++, y si esto fuera omnipresente, el PLA chino y la mafia eslava no estarían pirateando tantos sistemas informáticos occidentales. Pero históricamente, la mayoría de la programación C / C ++ ha descuidado la seguridad para el rendimiento. Lo más interesante es que la familia AS400 permitió que el sistema operativo creara punteros seguros, que podrían asignarse a código sin privilegios, pero que el código sin privilegios no podía falsificar ni alterar. Nuevamente, la seguridad, y aunque cumple con los estándares, muchos códigos C / C ++ descuidados que no cumplen con los estándares no funcionarán en un sistema tan seguro. De nuevo, hay estándares oficiales,
Ahora, saldré de mi caja de seguridad y mencionaré algunas otras formas en que los punteros (de varios tipos) a menudo no son realmente direcciones: punteros a miembros de datos, punteros a métodos de funciones de miembros y sus versiones estáticas son más grandes que un dirección ordinaria Como dice esta publicación :
Hay muchas formas de resolver esto [problemas relacionados con la herencia simple versus múltiple y la herencia virtual]. Así es como el compilador de Visual Studio decide manejarlo: un puntero a una función miembro de una clase con herencia múltiple es realmente una estructura ". Y continúan diciendo" ¡Al lanzar un puntero de función puede cambiar su tamaño! ".
Como probablemente pueda adivinar por mi pontificado en (in) seguridad, he estado involucrado en proyectos de hardware / software C / C ++ donde un puntero se trató más como una capacidad que como una dirección sin formato.
Podría seguir, pero espero que entiendas la idea.
BREVE RESUMEN
(que también pondré en la parte superior):
(0) pensar en los punteros como direcciones es a menudo una buena herramienta de aprendizaje, y es a menudo la implementación real de punteros a tipos de datos ordinarios.
(1) Pero en muchos, quizás la mayoría, los punteros de compiladores a funciones no son direcciones, sino que son más grandes que una dirección (normalmente 2X, a veces más), o en realidad son punteros a una estructura en la memoria que contiene las direcciones de función y cosas como Una piscina constante.
(2) Los punteros a los miembros de datos y los punteros a los métodos a menudo son aún más extraños.
(3) Código x86 heredado con problemas de puntero LEJOS y CERCA
(4) Varios ejemplos, especialmente el IBM AS / 400, con "punteros gordos" seguros.
Estoy seguro de que puedes encontrar más.