Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

276
Vistas
¿Está bien definida la conversión de puntero a través de un puntero vacío?

Supongamos que tengo algunas estructuras definidas como:

 struct foo { int a; }; struct bar { struct foo r; int b; }; struct baz { struct bar z; int c; };

¿El estándar C garantiza que el siguiente código es estrictamente conforme?

 struct baz x; struct foo *p = (void *)&x; assert(p == &x.zr);

La motivación de esta construcción es proporcionar un idioma de programación consistente para convertir a un tipo de puntero que se sabe que es compatible.


Ahora, esto es lo que dice C sobre cómo las estructuras y sus miembros iniciales son convertibles:

Dentro de un objeto de estructura, los miembros que no son campos de bits y las unidades en las que residen los campos de bits tienen direcciones que aumentan en el orden en que se declaran. Un puntero a un objeto de estructura, adecuadamente convertido, apunta a su miembro inicial (o si ese miembro es un campo de bits, entonces a la unidad en la que reside), y viceversa. Puede haber relleno sin nombre dentro de un objeto de estructura, pero no al principio.
C.11 §6.7.2.1¶15

Esto es lo que dice sobre las conversiones de puntero void :

Un puntero a void puede convertirse en o desde un puntero a cualquier tipo de objeto. Un puntero a cualquier tipo de objeto se puede convertir en un puntero para void y viceversa; el resultado se comparará igual al puntero original.
C.11 §6.3.2.3¶1

Y esto es lo que dice sobre la conversión entre tipos de punteros de objetos:

Un puntero a un tipo de objeto puede convertirse en un puntero a un tipo de objeto diferente. Si el puntero resultante no está correctamente alineado 68) para el tipo referenciado, el comportamiento no está definido. De lo contrario, cuando se vuelva a convertir, el resultado se comparará con el puntero original.

68) En general, el concepto ''correctamente alineado'' es transitivo: si un puntero de tipo A está correctamente alineado para un puntero de tipo B, que a su vez está correctamente alineado para un puntero de tipo C, entonces un puntero de tipo A está alineado correctamente para que un puntero escriba C.
C.11 §6.3.2.3¶7

Mi entendimiento de lo anterior es que convertir un puntero de objeto en un puntero de objeto de un tipo diferente a través de una conversión void * está perfectamente bien. Pero, recibí un comentario que sugiere lo contrario.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Su ejemplo es estrictamente conforme.

La segunda oración de §6.7.2.1 ¶15 ( Un puntero a un objeto de estructura, adecuadamente convertido, apunta a su miembro inicial... y viceversa. ) garantiza las siguientes igualdades:

 (sruct bar *) &x == &(xz) (struct foo *) &(xz) == &(xzr)

Como se encuentra al comienzo de la struct , no puede ocurrir ningún relleno, y mi comprensión del estándar es que la dirección de una struct y de su primer elemento son las mismas.

Entonces struct foo *p = (void *) &x; es correcto como lo sería struct foo *p = (struct foo *) &x;

En ese caso particular, se garantiza que la alineación sea correcta según §6.7.2.1 ¶15. Y siempre se permite pasar por un void * , pero no es necesario, porque §6.3.2.3 ¶7 permite la conversión entre punteros a diferentes objetos, siempre que no haya problema de alineación

Y debe tenerse en cuenta que §6.2.3.2 ¶7 también dice: Cuando un puntero a un objeto se convierte en un puntero a un tipo de carácter, el resultado apunta al byte direccionado más bajo del objeto , lo que significa que todos esos punteros apuntan en hecho al byte direccionado más bajo de xrza . Entonces, también podría pasar punteros a char porque también tenemos:

 (char *) &x == (char *) &(xz) == (char *) &(xzr) == (char *) &(xzra)
over 4 years ago · Santiago Trujillo Denunciar

0

Para completar el análisis, es necesario ver la definición de cómo se define la igualdad de punteros:

... Si un operando es un puntero a un tipo de objeto y el otro es un puntero a una versión calificada o no calificada de void , el primero se convierte al tipo del segundo.

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.
C.11 §6.5.9¶5-6

Entonces, aquí hay un argumento de que está bien definido:

(void *)&x == (void *)&x.z §6.7.2.1¶15, §6.5.9¶5-6
(void *)&x.z == &x.zr §6.7.2.1¶15, §6.5.9¶5-6
(void *)&x == &x.zr igualdad transitiva
(struct foo *)(void *)&x == (void *)&x §6.3.2.3¶1, §6.5.9¶5-6
(struct foo *)(void *)&x == &x.zr igualdad transitiva

El último paso anterior es la esencia de inicializar p y la afirmación del código en la pregunta.

over 4 years ago · Santiago Trujillo Denunciar

0

En mi humilde opinión, sí, aparte de lo que las interpretaciones estrictas del estándar pueden hacer cuestionables, la asignación de objetos en la memoria sigue la misma regla en el mismo compilador: proporcione una dirección adecuada para cualquier tipo de variable. Debido a que cada estructura comienza con su primera variable para la propiedad transitiva, la estructura misma se alineará con una dirección que se adapte a cualquier tipo de variable . Estos últimos cierran la duda de que diferentes estructuras tienen diferentes direcciones, no se puede hacer ninguna modificación entre conversiones porque la definición de la dirección sigue las mismas reglas . Por supuesto, eso no es cierto para los siguientes campos de estructura, que pueden no ser contiguos para cumplir con los requisitos de alineación de los siguientes campos. Si opera en el primer elemento de una estructura, se garantiza que es el mismo que el primer campo de la estructura misma .

Ahora eche un vistazo a una de las piezas de software más difundidas: el grupo JPEG independiente JPEGlib . Todo el software, compilado en muchos procesadores y máquinas, utiliza una técnica que se asemeja a la gestión de estructuras de paso de C++ cuyo comienzo es siempre el mismo, pero que contiene muchas otras subestructuras y campos diferentes entre llamadas.

Este código compila y se ejecuta en cualquier cosa, desde juguetes hasta PC, tabletas, etc.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda