2011-10-25 18 views
5

Esto es una continuación de this question.tipos de estructuras incompatibles en moldes/asignación?

que estoy tratando de evitar el uso de una explícita typedef copiar una matriz a otra a través de moldes de esta manera:

#include <stdio.h> 

int main(void) 
{ 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    *(struct{int _[3];}*)dst = *(struct{int _[3];}*)src; 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 
    return 0; 
} 

con gcc que estoy recibiendo arrcpy.c:8: error: incompatible types in assignment, sin embargo con Open Watcom que compila bien (y funciona como lo espero, imprimiendo de 1 a 3).

¿El comportamiento de gcc es estándar o no? Si lo es, ¿cuál es el capítulo y la sección relevante? No puedo entender por qué dos definiciones de tipo idénticas struct{int _[3];} no son las mismas (o compatibles) en los ojos de gcc.

EDIT: Sé muy bien que es un mal estilo de codificación. La pregunta es sobre una cosa diferente. Tengo curiosidad si hay una lógica lógica detrás del comportamiento del gcc, si es legítimo.

+0

Si eso es posible es una pregunta. Pero es absolutamente una manera horrible de escribir el código a menos que esté preparando su presentación para la competencia ofusca C. – TJD

+0

¿Por qué estás evitando el typedef? Ayudará a factorizar la especificación de estructura redundante. –

+3

¿Qué pasa con 'memcpy (3)'? – sarnold

Respuesta

6

El comportamiento de gcc es correcto, los tipos son dos estructuras sin nombre estructuras. Cada una de esas estructuras, aunque tiene el mismo diseño de memoria, tiene diferentes nombres. Si realmente quieres hacer eso, entonces usa un typedef.

+1

Incluso con el 'typedef', el tipo-juego de palabras daría lugar a ** comportamiento indefinido **. +1 de todos modos para abordar la pregunta de OP con una respuesta correcta sobre por qué el código es inválido en lugar de consejos sobre alternativas que OP parece ya entender "debería" ser utilizado. –

1

¿Por qué no usaría simplemente memcpy?

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    memcpy(dst, src, 3 * sizeof(int)); 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 
    return 0; 
} 

o por el tamaño, en lugar de 3: sizeof(dst)/sizeof(dst[0])

EDIT: Con su edición, sólo puedo suponer que, al igual que con outis' answer, el compilador ve las dos definiciones struct como sólo eso, dos diferentes tipos de estructuras Aunque pueden contener los mismos datos, son dos tipos diferentes.

+0

Sé cómo usar memcpy(). Ver la actualización de la pregunta. –

+0

Oh, ok, publicado antes de ver la edición. – AusCBloke

1

Básicamente, tipo de equivalencia no es structural equivalencia en C. C utiliza un nominative type system.

Según § 6.7.2.1-7 de C99:

La presencia de una declaración de lista de estructura en una estructura-o-union-especificador declara un nuevo tipo, dentro de una unidad de traducción. La struct-declaration-list es una secuencia de declaraciones para los miembros de la estructura o unión. Si struct-declaration-list no contiene miembros con nombre, el comportamiento no está definido. El tipo está incompleto hasta después de} que termina la lista.

struct-declaration-list y struct-or-union-specifier provienen de la gramática C (§ 6.7.2.1):

 
struct-or-union-specifier: 
    struct-or-union identifieropt { struct-declaration-list } 

struct-or-union: 
    struct 
    union 

Incluso si dos estructuras diferentes tienen el mismo diseño de la memoria, que son diferentes tipos.

Si desea evitar contaminar el espacio de nombre global, puede declarar la estructura localmente a la función en la que la usa.

#include <stdio.h> 

int main(void) { 
    // struct T is only visible in main() 
    struct T {int _[3];}; 
    int i; 
    int dst[] = { 10, 20, 30 }, src[] = { 1, 2, 3 }; 

    *(struct T*)dst = *(struct T*)src; 

    for (i = 0; i < 3; i++) printf("%d\n", dst[i]); 

    return 0; 
} 

void fails(void) { 
    // will cause a compilation error, because struct T is an incomplete type. 
    struct T t; 
} 
+2

La pregunta es sobre C, no C++ con sus clases y funciones sobrecargadas. –

+0

Y esta pregunta es lo suficientemente oscura que el hecho de que C y C++ son idiomas diferentes definitivamente importa. –

1

Los dos struct definiciones no son compatibles:

De C99 6.2.7:

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.5 para declaradores. Por otra parte, dos de estructura, unión, o tipos enumerados declarados en unidades de traducción separadas son compatibles si sus etiquetas y miembros de cumplir los siguientes requisitos ...

Los tipos no son lo mismo. Si se declararan en unidades de traducción separadas, serían compatibles, sin embargo.

Sin embargo, incluso si eran compatibles, su código todavía invocar un comportamiento indefinido, por al menos dos razones:

  1. Se utiliza el nombre "_" que está reservado.
  2. No se permite el acceso a objetos como un tipo diferente (excepto estructuras a través de punteros de caracteres, uniones, etc.).
+0

¿se refiere a 7.1.3 ?: 'Todos los identificadores que comienzan con un guión siempre están reservados para uso como identificadores con el ámbito de archivo tanto en el nombre común y la etiqueta spaces.' –

+0

@Alex: Sí, eso es todo. – wnoise

Cuestiones relacionadas