Skip to content

Instantly share code, notes, and snippets.

@mgarciaisaia
Created August 2, 2020 16:02
Show Gist options
  • Save mgarciaisaia/c5035faae9b989b0678127d8bae25144 to your computer and use it in GitHub Desktop.
Save mgarciaisaia/c5035faae9b989b0678127d8bae25144 to your computer and use it in GitHub Desktop.
El sistema de tipos de C no es súper maravilloso

En este ejemplo podemos ver algunas debilidades del sistema de tipos de C.

En particular, podemos ver que, cuando tenemos un puntero void *, el sistema de tipos no chequea demasiado a la hora de pasar ese puntero como parámetro a una función, generando incluso que la ejecución del programa sea errónea sin siquiera generar un warning.

¡Gracias a la banda del grupo de Telegram de UTNBA por levantar la discusión!

$ diff prueba2.c prueba.c
29c29
< printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
---
> // printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
$ gcc -Wall prueba2.c -lcommons -o prueba2
prueba2.c: In function 'main':
prueba2.c:29:52: warning: dereferencing 'void *' pointer
printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
^
prueba2.c:29:52: error: request for member 'cosito' in something not a structure or union
$ gcc prueba2.c -lcommons -o prueba2
prueba2.c: In function 'main':
prueba2.c:29:52: warning: dereferencing 'void *' pointer
printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
^
prueba2.c:29:52: error: request for member 'cosito' in something not a structure or union
$ gcc -Wall prueba.c -lcommons -o prueba
$ ./prueba
El cosito de el_coso es 42
El cosito de coso es 42
El cosito de (t_coso *)sera_un_coso es 42
El cosito de el_coso es 1065353216
El cosito de (t_coso *)sera_un_coso es 1065353216
#include <stdlib.h>
#include <stdio.h>
#include <commons/collections/list.h>
typedef struct {
int cosito;
} t_coso;
typedef struct {
float otra_cosa;
} t_no_es_un_coso;
void espera_un_coso(t_coso *el_coso) {
printf("El cosito de el_coso es %d\n", el_coso->cosito);
}
int main(void) {
t_coso *coso = malloc(sizeof(t_coso));
coso->cosito = 42; // siempre
t_no_es_un_coso *no_es_un_coso = malloc(sizeof(t_no_es_un_coso));
no_es_un_coso->otra_cosa = 1.0f;
t_list *cosas = list_create();
list_add(cosas, coso);
list_add(cosas, no_es_un_coso);
void *sera_un_coso = list_get(cosas, 0);
espera_un_coso(sera_un_coso); // esperaba que tire un warning grande como una casa, pero no. No entiendo por que.
printf("El cosito de coso es %d\n", coso->cosito); // anda, pero no pasó por la lista
printf("El cosito de (t_coso *)sera_un_coso es %d\n", ((t_coso *)sera_un_coso)->cosito); // anda, porque casteo
// printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
sera_un_coso = list_get(cosas, 1);
espera_un_coso(sera_un_coso); // como no se da cuenta de que son tipos distintos, compila y ejecuta, pero hace cualquiera
printf("El cosito de (t_coso *)sera_un_coso es %d\n", ((t_coso *)sera_un_coso)->cosito); // ejecuta, pero hace cualquiera
// printf("El cosito del coso es %d\n", sera_un_coso->cosito); // no compila, con o sin -Wall
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment