¿Todos los punteros se derivan de los punteros a los tipos de estructura de la misma?


La pregunta

La pregunta de si todos los punteros derivados de punteros a tipos de estructura son los mismos, no es fácil de responder. Me parece que es una pregunta importante por las siguientes dos razones principales.

A. La falta de un puntero a puntero a 'cualquier' tipo incompleto o de objeto, impone una limitación a las interfaces de función convenientes, tales como:

int allocate(ANY_TYPE  **p,
             size_t    s);

int main(void)
{
    int *p;
    int r = allocate(&p, sizeof *p);
}

[ejemplo de código Completo]

El puntero existente a' any ' incompleto o el tipo de objeto se describe explícitamente como:

C99 / C11 §6.3.2.3 p1:

Un puntero a void se puede convertir a o desde un puntero a cualquier tipo incompleto o de objeto. [...]

Un puntero derivado del puntero existente a 'cualquier' incompleto u tipo de objeto, puntero a puntero a vacío, es estrictamente un puntero a puntero a vacío, y no es necesario que sea convertible con un puntero derivado de un puntero a 'cualquier' incompleto u objeto tipo.


B. No es raro que los programadores utilicen convenciones basadas en suposiciones que no son requeridas, relacionadas con la generalización de punteros, a sabiendas o sin saberlo, mientras dependen de su experiencia con sus implementaciones específicas. Supuestos tales como ser convertible, ser representable como enteros, o compartir una propiedad común: tamaño del objeto, representación o alineación.


Las palabras del estándar

Según C99 §6.2.5 p27 / C11 §6.2.5 p28:

[...] Todos los punteros a tipos de estructura deberán tener los mismos requisitos de representación y alineación que los demás. [...]

Seguido de C99 TC3 Footnote 39 / C11 Footnote 48:

Los mismos requisitos de representación y alineación están destinados a implicar intercambiabilidad como argumentos a funciones, valores de retorno de funciones y miembros de uniones.

Aunque el estándar no dice: "Un puntero a un tipo de estructura" y el se han elegido las siguientes palabras: "Todos los punteros a tipos de estructura", no especifica explícitamente si se aplica a una derivación recursiva de dichos punteros. En otras ocasiones donde las propiedades especiales de los punteros se mencionan en el estándar, no especifica explícitamente o menciona la derivación recursiva del puntero, lo que significa que la 'derivación de tipo' se aplica, o no, pero no se menciona explícitamente.

Y aunque el fraseo "Todos los punteros a" al referirse to types se usa solo dos veces, (para tipos de estructura y unión), a diferencia del fraseo más explícito: "Un puntero a" que se usa en todo el estándar, no podemos concluir si se aplica a una derivación recursiva de tales punteros.

Author: lhunath, 2014-06-19

2 answers

Antecedentes

La suposición de que el estándar requiere implícitamente que todos los punteros a los tipos de estructura, (completo, incompleto, compatible e incompatible), tengan los mismos requisitos de representación y alineación, comenzó en C89 - muchos años antes de que el estándar lo requiriera explícitamente. El razonamiento detrás de esto era la compatibilidad de tipos incompletos en unidades de traducción separadas, y aunque de acuerdo con el comité de estándares C, la intención original era permitir el compatibilidad de un tipo incompleto con su variación completa, las palabras reales del estándar no lo describieron. Esto se ha modificado en el segundo corrigendum Técnico de C89, y por lo tanto concretó la suposición original.


Compatibilidad y Tipos Incompletos

Al leer las directrices relacionadas con la compatibilidad y los tipos incompletos, gracias a Matt McNabb, encontramos una mayor comprensión de la suposición original de C89.

Derivación de puntero de objeto y tipos incompletos

C99 / C11 §6.2.5 p1:

Los tipos se dividen en tipos de objeto, tipos de función y tipos incompletos.

C99 / C11 §6.2.5 p20:

Un tipo puntero puede derivarse de un tipo de función, un tipo de objeto o un tipo incompleto, llamado el tipo referenciado.

C99 / C11 §6.2.5 p22:

Un tipo de estructura o unión de contenido desconocido es un tipo incompleto. Está terminado, para todas las declaraciones de ese tipo, declarando la misma estructura o etiqueta de unión con su contenido definitorio más adelante en el mismo alcance.

Lo que significa que los punteros pueden derivarse tanto de tipos de objeto como de tipos incompletos. Aunque no se especifica que no es necesario completar los tipos incompletos, en el pasado el comité respondió sobre este asunto y afirmó que la falta de una prohibición es suficiente y no hay necesidad de una declaración positiva.

Lo siguiente puntero a puntero a 'struct never_completed' incompleta, nunca se completa:

int main(void)
{
    struct never_completed *p;
    p = malloc(1024);
}

[ejemplo de código Completo]

Tipos compatibles de unidades de traducción separadas

C99 / C11 §6.7.2.3 p4:

Todas las declaraciones de tipos structure, union o enumerated que tienen el mismo ámbito y utilizan la misma etiqueta declaran el mismo tipo.

C99 / C11 §6.2.7 p1:

Dos tipos tienen tipo compatible si sus tipos son igual. Dos tipos de estructura declarados en unidades de traducción separadas son compatibles si sus etiquetas (son) la misma etiqueta. [cita recortada] [...]

Este párrafo tiene un gran significado, permítanme resumirlo: dos tipos de estructura declarados en unidades de traducción separadas son compatibles si usan la misma etiqueta. Si ambos se completan, sus miembros deben ser los mismos (de acuerdo con las directrices especificadas).

Compatibilidad de punteros

C99 §6.7.5.1 p2 / C11 §6.7.6.1 p2:

Para que dos tipos de puntero sean compatibles, ambos deberán estar idénticos y ambos serán punteros a tipos compatibles.

Si el estándar exige que dos estructuras bajo condiciones específicas, sean compatibles en unidades de traducción separadas ya sea que estén incompletas o completas, significa que los punteros derivados de estas estructuras son compatibles igualmente.

C99 / C11 §6.2.5 p20:

Cualquier número de los tipos derivados se pueden construir a partir de los tipos objeto, función y incompletos

Estos métodos de construcción de tipos derivados se pueden aplicar recursivamente.

Y debido al hecho de que la derivación de punteros es recursiva, hace que los punteros derivados de punteros a tipos de estructura compatibles, sean compatibles entre sí.

Representación de tipos compatibles

C99 §6.2.5 p27 / C11 §6.2.5 p28:

Punteros a versiones cualificadas o no cualificadas de tipos compatibles deberán tener los mismos requisitos de representación y alineación.

C99 / C11 §6.3 p2:

La conversión de un valor de operando a un tipo compatible no causa ningún cambio en el valor o la representación.

C99 / C11 §6.2.5 p26:

Las versiones calificadas o no calificadas de un tipo son tipos distintos que pertenecen a la misma categoría de tipo y tienen la misma representación y alineación requisito.

Esto significa que una implementación conforme no puede tener un juicio distinto con respecto a los requisitos de representación y alineación de punteros derivados de tipos de estructura incompletos o completos, debido a la posibilidad de que una unidad de traducción separada pueda tener un tipo compatible, que tendrá que compartir los mismos requisitos de representación y alineación, y se requiere aplicar el mismo juicio distinto con variación del mismo tipo de estructura.

El siguiente puntero a puntero a incomplete 'struct complete_incomplete':

Struct complete_incomplete **p;

Es compatible y comparte los mismos requisitos de representación y alineación que el siguiente puntero a puntero a complete 'struct complete_incomplete':

Struct complete_incomplete {int i;} * * p;


C89 relacionados

Si nos preguntamos sobre la premisa relativa a C89, informe de defectos #059 de junio 93 ' cuestionado:

Ambas secciones no requieren explícitamente que un tipo incompleto eventualmente deba completarse, ni permiten explícitamente que los tipos incompletos permanezcan incompletos para toda la unidad de compilación. Dado que esta característica es importante para la declaración de tipos de datos opacos verdaderos, merece una aclaración.

Considerando las estructuras de referencia mutua definido e implementado en diferentes unidades de compilación hace que la idea de un tipo de datos opaco sea una extensión natural de un tipo de datos incompleto.

La respuesta del comité fue:{[57]]}

Los tipos de datos opacos fueron considerados y aprobados por el Comité al redactar la Norma C.


Compatibilidad versus Intercambiabilidad

Hemos cubierto el aspecto relativo a los requisitos de representación y alineación del puntero recursivo derivación de punteros a tipos de estructura, ahora nos enfrentamos a un asunto que una nota al pie no normativa mencionó, 'intercambiabilidad':

C99 TC3 §6.2.5 p27 Footnote 39 / C11 §6.2.5 p28 Footnote 48:

Los mismos requisitos de representación y alineación están destinados a implicar intercambiabilidad como argumentos a funciones, valores de retorno de funciones y miembros de uniones.

El estándar dice que las notas, notas al pie y ejemplos no son normativos y son " para información solo".

C99 FOREWORD p6 / C11 FOREWORD p8:

[...] este prólogo, la introducción, las notas, las notas al pie de página y los ejemplos también son solo para información.

Es lamentable que esta nota al pie de página confusa nunca se haya cambiado, porque en el mejor de los casos - la nota al pie se refiere específicamente a los tipos directos que se refieren a ella, por lo que la redacción de la nota al pie de página como-si las propiedades de "requisitos de representación y alineación" interpretar como una regla general para todos los tipos que comparten una representación y alineación. Si la nota a pie de página debe interpretarse sin el contexto de tipos específicos, entonces es obvio que el texto normativo de la norma no lo implica, incluso sin la necesidad de debatir la interpretación del término 'intercambiable'.

Compatibilidad de punteros con tipos de estructura

C99 / C11 §6.7.2.3 p4:

Todas las declaraciones de estructura, unión o tipos enumerados que tienen el mismo ámbito y usan la misma etiqueta declaran el mismo tipo.

C99 / C11 §6.2.7 p1:

Dos tipos tienen un tipo compatible si sus tipos son los mismos.

C99 §6.7.5.1 p2 / C11 §6.7.6.1 p2:

Para que dos tipos de puntero sean compatibles, ambos deberán estar idénticos y ambos serán punteros a tipos compatibles.

Esto establece la conclusión obvia, diferentes tipos de estructura son de hecho diferentes tipos, y porque son diferentes son incompatibles. Por lo tanto, dos punteros a dos tipos diferentes e incompatibles, también son incompatibles, independientemente de sus requisitos de representación y alineación.

Tipos efectivos

C99 / C11 §6.5 p7:

Un objeto tendrá acceso a su valor almacenado solo mediante una expresión lvalue que tenga uno de los siguientes tipos:

Un tipo compatible con el tipo efectivo del objeto

C99 / C11 §6.5 p6:

El tipo efectivo de un objeto para un acceso a su valor almacenado es el tipo declarado del objeto, si lo hay.

Los punteros incompatibles no son 'intercambiables' como argumentos para funciones, ni como valores de retorno de funciones. Las conversiones implícitas y los casos especiales especificados son las excepciones, y estos tipos no forman parte de ninguna de dichas excepciones. Incluso si decidimos añadir un requisito poco realista para dicha 'intercambiabilidad', y decir que se requiere una conversión explícita para hacerla aplicable, y luego acceder al valor almacenado de un objeto con un tipo efectivo incompatible rompe las reglas de tipos efectivos. Para hacerlo realidad necesitamos una nueva propiedad que actualmente el estándar no tiene. Por lo tanto, compartir los mismos requisitos de representación y alineación, y ser convertible, simplemente no es suficiente.

Esto nos deja con ser intercambiables 'como miembros de sindicatos', y aunque son de hecho intercambiable como miembros de la unión - no tiene ningún significado especial.

Interpretaciones oficiales

1. La primera interpretación "oficial" pertenece a un miembro del comité de normas C. Su interpretación para: "están destinados a implicar intercambiabilidad", es que en realidad no implica que tal intercambiabilidad existe, sino que en realidad hace una sugerencia para ello.

Por mucho que me gustaría que se hiciera realidad, no consideraría una implementación que tomó una sugerencia de una nota de pie de página no normativa, por no mencionar una nota de pie de página injustificadamente vaga, al tiempo que contradice las directrices normativas-para ser una implementación conforme. Esto obviamente hace que un programa que utiliza y depende de tal "sugerencia", sea no estrictamente conforme.

2. La segunda interpretación 'oficial' pertenece a un miembro / colaborador del comité de estándares C, por su interpretación la nota a pie de página no introduce una sugerencia, y debido a que el texto (normativo) del estándar no lo implica, él lo considera un defecto en el estándar. Incluso sugirió que se modificaran las reglas de tipos eficaces para abordar esta cuestión.

3. La tercera interpretación 'oficial' es del informe de defectos #070 de Diciembre 93`. Se ha preguntado, dentro del contexto de C89, si un programa que pasa un tipo 'unsigned int', donde se espera el tipo 'int', como un argumento a una función con un declarador no prototipo, para introducir un comportamiento indefinido.

En C89 hay la misma nota al pie, con la misma intercambiabilidad implícita como argumentos a funciones, adjunta a: {[57]]}

C89 §3.1.2.5 p2:

El rango de valores no negativos de un tipo entero con signo es un subrango del tipo entero sin signo correspondiente, y la representación del mismo valor en cada tipo es la misma.

El comité respondió que alentaba a los ejecutores a permitir que esta intercambiabilidad funcione, pero como no es un requisito, hace que el programa no sea estrictamente conforme.


El siguiente ejemplo de código no es estrictamente conforme. '&s1' y 'struct generic * *' comparten los mismos requisitos de representación y alineación, pero no obstante son incompatibles. De acuerdo con las reglas de tipos efectivos, estamos accediendo al valor almacenado del objeto ' s1 ' con un tipo efectivo incompatible, un puntero a 'struct generic', mientras que su tipo declarado, y por lo tanto tipo efectivo, es un puntero a 'struct s1'. Para superar esta limitación podríamos haber utilizado los indicadores como miembros de un sindicato, pero esta convención daña el objetivo de ser genérico.

int allocate_struct(void    *p,
                    size_t  s)
{
    struct generic **p2 = p;
    if ((*p2 = malloc(s)) == NULL)
        return -1;

    return 0;
}

int main(void)
{
    struct s1 { int i; } *s1;

    if (allocate_struct(&s1, sizeof *s1) != 0)
        return EXIT_FAILURE;
}

[ejemplo de código Completo]


El siguiente ejemplo de código es estrictamente conforme, para superar ambos problemas de tipos efectivos y ser genéricos, estamos aprovechando: 1. un puntero al vacío, 2. el requisitos de representación y alineación de todos los punteros a estructuras, y 3. acceder a la representación de bytes del puntero 'genéricamente', mientras se usa memcpy para copiar la representación, sin afectar su tipo efectivo.

int allocate_struct(void    *pv,
                    size_t  s)
{
    struct generic *pgs;

    if ((pgs = malloc(s)) == NULL)
        return -1;

    memcpy(pv, &pgs, sizeof pgs);
    return 0;
}

int main(void)
{
    struct s1 { int i; } *s1;

    if (allocate_struct(&s1, sizeof *s1) != 0)
        return EXIT_FAILURE;
}

[ejemplo de código Completo]


La Conclusión

La conclusión es que una implementación conforme debe tener los mismos requisitos de representación y alineación, respectivamente, para todos los punteros derivados recursivamente a tipos de estructura, si son incompletos o completos, y si son compatibles o incompatibles. Aunque si los tipos son compatibles o incompatibles es significativo, pero debido a la mera posibilidad de un tipo compatible, deben compartir las propiedades fundamentales de representación y alineación. Hubiera sido preferible si pudiéramos acceder a punteros que comparten representación y alineación directamente, pero desafortunadamente las reglas actuales de tipos efectivos no lo requieren.

 28
Author: Dror K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-26 20:16:49

Mi respuesta es "no."

No hay ninguna redacción en ningún estándar de C que yo sepa que sugiera lo contrario. El hecho de que todos los punteros a tipos de estructura tengan los mismos requisitos de representación y alineación no tiene relación con ningún tipo derivado.

Esto tiene sentido completo y cualquier otra realidad parecería ser inconsistente. Considere la alternativa:

Llamemos a los requisitos de alineación y representación para los punteros a los tipos de estructura "A". Supongamos que cualquier "tipo derivado recursivamente" comparte los requisitos "A".

Llamemos "B"a los requisitos de alineación y representación para punteros a tipos de unión. Supongamos que cualquier" tipo derivado recursivamente "comparte los requisitos "B".

Supongamos que "A" y "B" no son lo mismo[1]. Además, supongamos que no pueden ser satisfechos al mismo tiempo. (Una representación de 4 bytes y una representación de 8 bytes, por ejemplo.)

Ahora derive un tipo de ambos:

  1. Un tipo con requisitos"A"
  2. Un tipo con requisitos"B"

Ahora tenemos un tipo cuyos requisitos son imposibles de satisfacer, porque debe satisfacer "A" y "B", pero ambos no pueden satisfacerse a la vez.

Tal vez usted está pensando en los tipos derivados como tener un linaje plano todo el camino de vuelta a un solo ancestro, pero eso no es así. Los tipos derivados pueden tener muchos ancestros. La definición estándar de" tipos derivados " discute este.

[1] Si bien puede parecer irrazonable, improbable y tonto, está permitido.

 1
Author: synthetel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-24 06:15:29