Puntero de desreferenciación a error de tipo incompleto en C

Jay Shaw 12 octubre 2023
  1. Causas del error desreferenciar puntero a tipo incompleto en C
  2. Tipos incompletos en C
  3. Referenciar y desreferenciar un puntero en C
  4. Resolver el error desreferenciar puntero a tipo incompleto en C
  5. Conclusión
Puntero de desreferenciación a error de tipo incompleto en C

Se sabe que se utiliza un puntero para almacenar la dirección de los valores almacenados dentro de una variable. Esta variable de puntero se puede hacer referencia a una variable para obtener su dirección o se puede desreferenciar para acceder a su valor.

Pero cuando este puntero necesita ser visto o editado, debe ser desreferenciado. Cuando esta desreferenciación se realiza a través de un tipo declarado pero no definido, arroja el error desreferenciación de puntero a tipo incompleto.

Causas del error desreferenciar puntero a tipo incompleto en C

Este error se produce cuando el compilador se encuentra con un puntero al que se le ha quitado la referencia a una estructura. Cuando el compilador se mueve hacia la estructura, la encuentra incompleta, es decir, no definida correctamente.

El compilador arroja diferentes errores cuando se llama a una estructura indefinida para deferenciar un puntero. El tipo de error encontrado depende del compilador utilizado.

el error desreferenciar puntero a tipo incompleto en el compilador GCC

Por ejemplo, una estructura indefinida se ve así:

struct circle {
  int length;
};
int main() {
  struct round *x = 0;
  *x;
}

En el programa C anterior, se puede observar que se construye una estructura círculo, pero la estructura llamada dentro de la función main tiene el nombre redondo.

Dentro de la función main, se crea un puntero de objeto *x a partir de la estructura round. Por último, se llama al objeto puntero.

Aquí, una estructura incompleta se usa como si fuera una estructura completa, lo que hace que el compilador arroje el error.

1035906452/source.c: In function 'main':
1035906452/source.c:6:5: error: dereferencing pointer to incomplete type 'struct round'
     *x;
     ^~

Se puede observar que el compilador arroja el error desreferenciando puntero a tipo incompleto.

Normalmente, C encontrará el nombre de la estructura que se colocó; si no se encuentra la estructura original, normalmente aparecería. También aparecerá si apunta un puntero hacia ese puntero.

Este error suele aparecer si el nombre de su estructura es diferente de la inicialización de su estructura en el código.

Una estructura también puede arrojar errores cuando se le asigna un alias que el compilador no puede leer, pero eso no sucede con todos los compiladores.

el error desreferenciar puntero a tipo incompleto en Clang Compiler

Esto se encuentra cuando el mismo código se ejecuta a través de un compilador de Clang.

1790191360/source.c:6:5: error: incomplete type 'struct round' where a complete type is required
    *x;
    ^
1790191360/source.c:5:12: note: forward declaration of 'struct round'
    struct round *x = 0;
           ^
1790191360/source.c:6:5: warning: expression result unused [-Wunused-value]
    *x;
    ^~
1 warning and 1 error generated.

Aquí, el compilador llama a la estructura incompleta pero deja el puntero desreferenciado como una advertencia en lugar de un error.

Entender por qué ocurre el error desreferenciar puntero a tipo incompleto requiere conocer dos conceptos.

  1. ¿Qué son los tipos incompletos?
  2. ¿Qué significa desreferenciar un puntero?

Tipos incompletos en C

Un tipo declarado pero no especificado está incompleto (en el caso de tipos de estructura).

Los errores tipográficos en los nombres de tipo, que impiden que el compilador haga coincidir un nombre con otro, son una causa común de errores de tipo incompletos en el lenguaje C (como al hacer coincidir la declaración con la definición).

Es un error pensar que un tipo incompleto es un tipo faltante. Los tipos incompletos también pueden ocurrir fuera de la estructura.

Tres escenarios causan tipo incompleto:

  1. Un tipo de estructura sin miembros.
  2. Un tipo de unión sin miembros.
  3. Una matriz que se declara pero no se inserta ningún elemento.

Crear un tipo incompleto y definirlo

Una estructura o un tipo similar necesita especificarse con la información que falta para completar un tipo incompleto.

La creación y finalización de los tipos incompletos se muestran en los siguientes ejemplos.

Declare un tipo de estructura pero omita los miembros para producir un tipo de estructura incompleto. El puntero x en esta ilustración apunta a un tipo de estructura incompleta llamada biblioteca.

struct library *x;

Declare el mismo tipo de estructura más adelante en el mismo ámbito con sus miembros proporcionados para completar un tipo de estructura incompleto.

struct library {
  int book_id;
  char book_name[50];
}

Para crear una matriz de tipos incompletos, declare un tipo de matriz sin especificar su número de repeticiones. Por ejemplo:

char book_name[]; /* book_name has incomplete type */

Declare el mismo nombre más tarde en el mismo ámbito con su recuento de repeticiones establecido para finalizar un tipo de matriz incompleta.

char book_name[25]; /* book_name now has complete type */

Una vez que hemos entendido cómo se completan los tipos incompletos, podemos pasar a la segunda parte de resolver el error desreferenciar puntero a tipo incompleto.

Referenciar y desreferenciar un puntero en C

La función de un puntero es almacenar la dirección de un valor, lo que significa que almacena una referencia a algo. El objeto al que apunta un puntero se llama pointee.

Hacer referencia a un puntero en C

Hay dos etapas distintas involucradas en la asignación de un puntero y un pointee al que apuntará. Se puede pensar que la estructura puntero/apuntado tiene dos niveles de operación.

Todo debe configurarse en ambos niveles para que funcione. El error más frecuente es concentrarse en escribir código que manipule el nivel del puntero sin configurar el nivel del puntero.

Las operaciones de puntero que no hacen contacto con las puntas a veces se denominan operaciones “superficiales”, mientras que las que sí lo hacen se denominan operaciones “profundas”.

Considere el siguiente código:

Se crea un puntero ptr_a dentro de la función main. Este puntero se crea pero no puede almacenar nada a menos que se asigne un punto o un fragmento de memoria.

La asignación de memoria se realiza mediante malloc, y el tamaño dado es equivalente al tipo de datos int.

void main() {
  int* ptr_a;  // Allocate the pointer

  ptr_a = malloc(
      sizeof(int));  // Allocate an int pointee, and set ptr_a to point to it
}

Código C++:

int main() {
  int* ptr_a;  // Allocate the pointer ptr_a

  ptr_a = new int;  // Allocate an int pointee, and set ptr_a to point to it
}

Desreferenciando un puntero en C

Las operaciones de desreferenciación comienzan en el puntero y siguen hasta el apuntado. El objetivo podría ser examinar o modificar el estado de las puntas.

Un puntero solo se puede desreferenciar si tiene una punta; el pointee también debe asignarse antes de que el puntero pueda señalarlo. Olvidarse de configurar la pointee es el error más frecuente en los programas de punteros.

La falla en el código para desreferenciar con éxito un puntero es el bloqueo de tiempo de ejecución más común. El sistema de tiempo de ejecución en Java señala el problema de las desreferencias incorrectas con advertencias menores.

En lenguajes compilados como C y C++, una desreferencia incorrecta puede provocar un bloqueo o una corrupción espontánea de la memoria. Esto hace que sea difícil encontrar problemas de puntero en lenguajes compilados.

Código C:

Una vez que se asigna la memoria y se apunta hacia el puntero ptr_a, se almacena un valor dentro de ella desreferenciandola.

void main() {
  int* ptr_a;

  ptr_a = malloc(
      sizeof(int));  // Allocate an int pointee, and set ptr_a to point to it

  *ptr_a = 42;  // Dereference ptr_a to store 42 in its pointee
}

Código C++:

int main() {
  int* ptr_a;  // Allocate the pointers

  ptr_a = new int;  // Allocate an int pointee, and set ptr_a to point to it

  *ptr_a = 42;  // Dereference ptr_a to store 42 in its pointee
}

Punteros compartidos en C

Cuando se asignan dos punteros al mismo señalador, ambos apuntarán allí. Como resultado, y apunta a la misma punta que x cuando y = x.

Las puntas no se ven afectadas por la asignación de punteros.

Solo modifica un puntero para compartir la misma referencia que otro. Después de la asignación del puntero, se considera que los dos punteros “comparten” al señalado.

Código C:

void main() {
  int* ptr_a;
  int* ptr_b;

  ptr_a = malloc(sizeof(int));

  *ptr_a = 42;

  *ptr_b = 13;  // CRASH -- ptr_b does not have a pointee yet

  ptr_b = ptr_a;  // Pointer assignment sets ptr_b to point to ptr_a's pointee

  *ptr_b = 13;  // Dereference ptr_b to store 13 in its (shared) pointee
}

Hemos entendido los dos conceptos detrás de la solución del error desreferenciar puntero a tipo incompleto. Ahora veremos los códigos que encuentran el error y cómo resolver el problema.

Resolver el error desreferenciar puntero a tipo incompleto en C

El siguiente programa tiene una estructura rectángulo con un miembro entero longitud. El nombre de la estructura se hace deliberadamente diferente al que está dentro de la función main para crear un tipo incompleto.

Dentro de la función main, se crea el puntero *a y se le asigna memoria del tamaño del rectángulo de la estructura, y luego se apunta hacia él.

Luego, el puntero se usa para desreferenciar el miembro de estructura longitud para almacenar un valor dentro de él. Como la estructura es de tipo incompleto, debe arrojar un error de desreferenciación de puntero a tipo incompleto.

#include <stdio.h>
#include <stdlib.h>

struct rectangle {
  int length;
};

int main() {
  struct square *a;
  a = (struct rectngle *)malloc(sizeof(struct rectngle));
  a->length = 33;
  printf("%d", *a);
}

Producción :

1647679200/source.c: In function 'main':
1647679200/source.c:10:38: error: invalid application of 'sizeof' to incomplete type 'struct rectngle'
  a = (struct rectngle*)malloc(sizeof(struct rectngle));
                                      ^~~~~~
1647679200/source.c:11:3: error: dereferencing pointer to incomplete type 'struct square'
  a->length = 33;
   ^~

El tipo incompleto debe completarse para resolver este problema, que en este caso es la estructura rectngle.

Estos cambios deben realizarse para completar una estructura incompleta y desreferenciar sus miembros a través de un puntero dentro de la función main.

#include <stdio.h>
#include <stdlib.h>

struct rectangle {  // a struct rectngle is created
  int length;
};

int main() {
  struct rectangle *a;  // name of struct inside main() is same as above struct

  a = (struct rectangle *)malloc(sizeof(
      struct rectangle)); /*pointer allocated memory and
                                                                   pointer
                             to pointer 'a'.   */

  a->length = 33;  // pointer deferenced.

  printf("%d", *a);  // value of pointer dereferenced
}

Producción :

33

Conclusión

Este artículo arroja luz sobre el error que surge debido a la desreferenciación del puntero al tipo incompleto. Después de leer este artículo, el lector puede consultar y deferir fácilmente punteros y completar tipos incompletos.

Artículo relacionado - C Error