sirven que punteros puntero para los declaracion cadenas aritmetica apuntadores c pointers language-lawyer incomplete-type

punteros - ¿Es &*p válido C, dado que p es un puntero a un tipo incompleto?



punteros c++ (3)

¿El siguiente ejemplo es una unidad de traducción completa válida en C?

struct foo; struct foo *bar(struct foo *j) { return &*j; }

struct foo es un tipo incompleto, pero no puedo encontrar una prohibición explícita de desreferenciar un tipo incompleto en el estándar C. En particular, §6.5.3.2 dice:

El operador unario arroja la dirección de su operando. Si el operando tiene el tipo '''' tipo '''', el resultado tiene el tipo '''' puntero para escribir ''''. Si el operando es el resultado de un operador unario * , ni ese operador ni el operador & se evalúan y el resultado es como si ambos se hubieran omitido, excepto que las restricciones sobre los operadores todavía se aplican y el resultado no es un valor l.

El hecho de que el resultado no sea un valor l no es pertinente; los valores de retorno no tienen por qué serlo. Las restricciones en el operador * son simplemente:

El operando del operador unario * tendrá un tipo de puntero.

y en el operador & son:

El operando del operador unario será un designador de función, el resultado de un operador [] o unario * , o un valor l que designa un objeto que no es un campo de bits y no se declara con el especificador de clase de almacenamiento de register .

Ambos están trivialmente satisfechos aquí, por lo que el resultado debería ser equivalente a simplemente return j; .

Sin embargo, gcc 4.4.5 no compila este código. En su lugar, da el siguiente error:

y.c:5: error: dereferencing pointer to incomplete type

¿Es esto un defecto en gcc?


El estándar C99 (ISO / IEC 9899: 1999) describe el comportamiento:

§6.5.3.2 Operadores de dirección e indirección

El operador unario devuelve la dirección de su operando. Si el operando tiene el tipo '''' tipo '''', el resultado tiene el tipo '''' puntero para escribir ''''. Si el operando es el resultado de un operador unario *, ni ese operador ni el operador & se evalúan y el resultado es como si ambos se hubieran omitido, excepto que las restricciones sobre los operadores todavía se aplican y el resultado no es un valor l.

Esto significa que &*j es equivalente a j .

Sin embargo, j se supone que es un puntero a un objeto, y es solo un puntero a un tipo incompleto, como dice GCC 4.4.5.

§6.3.2.3 Punteros

Un puntero a void se puede convertir desde o hacia un puntero a cualquier tipo incompleto o de objeto. Un puntero a cualquier tipo incompleto o de objeto se puede convertir a un puntero a vacío y viceversa; el resultado se comparará igual al puntero original.

Tenga en cuenta que distingue entre un tipo de objeto y un tipo incompleto; esto ocurre frecuentemente en el estándar.

Entonces, esta observación en la pregunta es incorrecta:

Ambos están trivialmente satisfechos aquí,

La variable j no es un puntero a un objeto; es un puntero a un tipo incompleto, que no es un objeto.

§6.2.5 Tipos

[...] Los tipos se dividen en tipos de objetos (tipos que describen completamente los objetos), tipos de funciones (tipos que describen funciones) y tipos incompletos (tipos que describen objetos pero carecen de la información necesaria para determinar sus tamaños).


Sí, creo que es un error. Incluso lvalues ​​de tipos incompletos, por lo que *j , parecen permitirse dependiendo del contexto:

6.3.2.1 ... Un lvalue es una expresión con un tipo de objeto o un tipo incompleto distinto de vacío

Básicamente esto debería funcionar siempre y cuando no se haga nada con un valor l que necesite conocer sobre la estructura de la struct . Entonces, si no accede al objeto o pregunta sobre su tamaño, esto es legal.


Sí. Los punteros en C generalmente tienen el mismo tamaño (en algunos sistemas integrados, pueden ser diferentes). Esto significa que el compilador puede generar el código de ensamblador correcto para esto aunque el tipo sea "desconocido".

Puede usar este enfoque para ocultar completamente la estructura de datos interna al exterior. Use un typedef para declarar un puntero a una estructura y solo declare la estructura en sus archivos de encabezado internos (es decir, los archivos que no son parte de su API pública).

La razón por la que gcc 4.4.5 se queja es solo eso: si utiliza punteros para el tipo incompleto fuera de la implementación, debería funcionar. Pero el código es parte de la implementación y aquí, es probable que desee tener el tipo completo.