vectores todos tipos que punteros puntero operaciones nulo nombres matrices los funciones ejemplos con comparar clasificacion arreglo aritmetica c pointers struct initialization incompatibletypeerror

todos - C-Tipo de puntero incompatible



tipos de punteros (3)

¿Por qué el siguiente código da advertencias?

int main(void) { struct {int x; int y;} test = {42, 1337}; struct {int x; int y;} *test_ptr = &test; }

Resultados:

warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] struct {int x; int y;} *test_ptr = &test; ^


C se diseñó originalmente para que los punteros a estructuras con diseños parcial o totalmente idénticos pudieran usarse indistintamente para acceder a las partes comunes, y las versiones del lenguaje anteriores a C89 que implementaban espacios de nombres individuales para miembros de la estructura generalmente conservaban la capacidad de usar los punteros de manera intercambiable con la ayuda de typecasts, conversiones a través de vacío, etc. Si bien sería legal para los compiladores insertar diferentes cantidades de relleno antes de diferentes tamaños de matriz, la mayoría de los compiladores especifican que realizan el diseño sin hacerlo, lo que significa que uno podría escribir fácilmente un función que aceptaría un puntero a cualquiera de los siguientes objetos, o cualquier otra cosa declarada de manera similar (de tamaño 4, 5, 24601, etc.)

struct { int size; int foo[2]; } my_two_foos = {2, {1,2} }; struct { int size; int foo[3]; } my_three_foos = {3, {4,5,6} };

Como las implementaciones no estaban obligadas a ofrecer garantías sobre el diseño que hicieran indispensables tales construcciones, los autores de la Norma declinaron exigir que los compiladores reconozcan cualquier concepto de compatibilidad de diseño, ya que esos compiladores serían indispensables (p. Ej. Aquellos en los que las estructuras al igual que el anterior se presentaría de manera consistente) ya lo apoyaba, y no había ninguna razón para creer que no continuarían haciéndolo, independientemente de si el Estándar lo ordenaba o no. El factor determinante para determinar si una característica o garantía debería ser obligatoria no era si los costos serían superiores a los beneficios en plataformas que podrían respaldar esa característica o garantía de manera económica y sencilla, sino si los costos en plataformas donde el soporte sería más caro y mínimamente útil sería compensado por los beneficios en esas mismas plataformas .

Desafortunadamente, los escritores de compiladores han perdido de vista el hecho de que el Estándar solo define lo que es necesario para que una implementación sea "compatible" y no define qué características hacen que algo sea un buen compilador para una plataforma dada, y como consecuencia tienen se vuelven cada vez más agresivos al encontrar excusas para ignorar los precedentes en plataformas donde las conductas se han apoyado durante décadas a un costo mínimo. Como consecuencia, el código que se basa en comportamientos que solían ser comunes puede funcionar correctamente si se utilizan opciones de compilación como -fno-strict-aliasing que deshabilitan muchas más optimizaciones de las que habría sido necesario al usar un compilador menos agresivo.


Son dos tipos de estructura anónima (ni tienen etiqueta). Todos los tipos de estructura (en una sola unidad de traducción) son distintos: nunca son del mismo tipo. ¡Añadir una etiqueta!

La oración relevante en el estándar está en §6.7.2.1 Estructura y especificadores de unión :

¶8 La presencia de una struct-declaration-list en un struct-o-union-specifier declara un nuevo tipo, dentro de una unidad de traducción.

La struct-declaration-list se refiere al material entre { y } en el tipo.

Eso significa que en su código, hay dos tipos separados, uno para cada struct { … } . Los dos tipos están separados; no puede asignar oficialmente un valor de un tipo al otro, ni crear punteros, etc. De hecho, no puede hacer referencia a esos tipos nuevamente después del punto y coma.

Eso significa que podrías tener:

int main(void) { struct {int x; int y;} test = {42, 1337}, *tp = &test; struct {int x; int y;} result, *result_ptr; result_ptr = &result; … }

Ahora test y tp refieren al mismo tipo (uno una estructura, uno un puntero a la estructura) y, de manera similar, result y result_ptr referencia al mismo tipo, y las inicializaciones y asignaciones son correctas, pero los dos tipos son diferentes. No está claro si crea un literal compuesto de cualquier tipo; debe escribir (struct {int x; int y;}){.y = 9, .x = 8} , pero la presencia de la estructura-declaración -list significa que es otro tipo nuevo.

Como se señala en los comentarios, también hay una sección §6.2.7 Tipo compatible y tipo compuesto , que dice:

¶1 ... Además, dos tipos de estructura, unión o enumerados declarados en unidades de traducción separadas son compatibles si sus etiquetas y miembros satisfacen los siguientes requisitos: Si uno se declara con una etiqueta, el otro se declarará con la misma etiqueta. Si ambos se completan en cualquier lugar dentro de sus respectivas unidades de traducción, se aplicarán los siguientes requisitos adicionales: habrá una correspondencia uno a uno entre sus miembros, de modo que cada par de miembros correspondientes se declare con tipos compatibles; si un miembro del par se declara con un especificador de alineación, el otro se declara con un especificador de alineación equivalente; y si un miembro del par se declara con un nombre, el otro se declara con el mismo nombre. Para dos estructuras, los miembros correspondientes se declararán en el mismo orden. Para dos estructuras o uniones, los campos de bits correspondientes deben tener el mismo ancho.

Hablando en términos generales, eso dice que si las definiciones de los tipos en las dos unidades de traducción (piense en ''archivos fuente'' más los encabezados incluidos) son las mismas, entonces se refieren al mismo tipo. ¡Gracias a Dios por eso! De lo contrario, no podría tener la biblioteca de E / S estándar funcionando, entre otros detalles menores.


Variables &test y test_ptr , que son estructuras anónimas, tienen diferentes tipos.

Las estructuras anónimas definidas en la misma unidad de traducción nunca son tipos compatibles 1, ya que el Estándar no define la compatibilidad para dos definiciones de tipo de estructura en la misma unidad de traducción.

Para compilar tu código, podrías hacer:

struct {int x; int y;} test = {42, 1337} , *test_ptr; test_ptr = &test;

1 (Citado de: ISO: IEC 9899: 201X 6.2.7 Tipo compatible y tipo compuesto 1)
Dos tipos tienen un tipo compatible si sus tipos son los mismos. Las reglas adicionales para determinar si dos tipos son compatibles se describen en 6.7.2 para especificadores de tipo, en 6.7.3 para calificadores de tipo y en 6.7.6 para declaradores. Además, dos tipos de estructura, unión o enumerados declarados en unidades de traducción separadas son compatibles si sus etiquetas y miembros satisfacen los siguientes requisitos: Si uno se declara con una etiqueta, el otro se declarará con la misma etiqueta. Si ambos se completan en cualquier lugar dentro de sus respectivas unidades de traducción, se aplicarán los siguientes requisitos adicionales: habrá una correspondencia uno a uno entre sus miembros, de modo que cada par de miembros correspondientes se declare con tipos compatibles; si un miembro del par se declara con un especificador de alineación, el otro se declara con un especificador de alineación equivalente; y si un miembro del par se declara con un nombre, el otro se declara con el mismo nombre. Para dos estructuras, los miembros correspondientes se declararán en el mismo orden. Para dos estructuras o uniones, los campos de bits correspondientes deben tener el mismo ancho. Para dos enumeraciones, los miembros correspondientes tendrán los mismos valores.