Search code examples
ccastingwarningscompiler-warnings

Silence WCast-function-type on a function structure


I have the following warning :

cast between incompatible function types from ‘int (*)(pile *)’ {aka ‘int (*)(struct pile *)’} to ‘void (*)(void *)’ [-Wcast-function-type] 

I don't have any idea of how I can fix this warning.

Structure

typedef struct conteneur_sommets {
  void *donnees;
  int (*est_vide)(void *);
  void (*ajouter)(void *, int);
  void (*supprimer)(void *);
  int (*choisir)(void *);
  void (*detruire)(void *);
} conteneur_sommets;

associated function

conteneur_sommets *cs_creer_pile(int n)
{
  conteneur_sommets cs = {.donnees   = pile_creer(n),
              .est_vide  = (int (*)(void *))        pile_est_vide,
              .ajouter   = (void (*)(void *, int))  pile_empiler,
              .supprimer = (void (*)(void *))       pile_depiler, <- warning cast
              .choisir   = (int (*)(void *))        pile_sommet,
              .detruire  = (void (*)(void *))       pile_detruire};
  return cs_creer(&cs);
}

void cs_supprimer(conteneur_sommets *cs)
{
  cs->supprimer(cs->donnees);
}

Solution

  • While suppressing the warning completely can sometimes be usefull, it is better in general to fix the issue at the code level. The issue here is that your declarations are wrong which is reason the warning is triggered in the first place. First avoid to combine the definition of a struct/union and the declaration of the typedef alias. It is better to separate them, this way you can, if necessary separate declaration and definition.

    typedef struct conteneur_sommets conteneur_sommets;
    

    This creates the alias conteneur_sommets to the opaque structure struct conteneur_sommets. This is also called a forward declaration. The forward declaration is generally put in the header file.

    Now we can define the structure

    struct conteneur_sommets {
        void *donnees;
        int (*est_vide)(conteneur_sommets *);
        void (*ajouter)(conteneur_sommets *, int);
        void (*supprimer)(conteneur_sommets *);
        int (*choisir)(conteneur_sommets *);
        void (*detruire)(conteneur_sommets *);
    };
    

    This way you don't need to cast the function pointer and conserve type checks if it is of the right signature.

    conteneur_sommets cs = {.donnees   = pile_creer(n),
              .supprimer = pile_depiler};
    

    Secondly A thing that is seldom realized by C programmers is that one can define typedef aliases of function prototypes, not function pointers but directly of prototypes. This can sometime really make the code much more readable even if quite unusual. Let me give you an example with your code:

    typedef int  est_vide_fn (conteneur_sommets *);
    typedef void ajouter_fn  (conteneur_sommets *, int);
    typedef void supprimer_fn(conteneur_sommets *);
    typedef int  choisir_fn  (conteneur_sommets *);
    typedef void detruire_fn (conteneur_sommets *);
    

    this declares five function prototype type definitions.

    the structure can now be declared as

    struct conteneur_sommets {
        void *donnees;
        est_vide_fn  *est_vide;
        ajouter_fn   *ajouter;
        supprimer_fn *supprimer;
        choisir_fn   *choisir;
        detruire_fn  *detruire;
    };
    

    Your cs_supprimer functions prototype can be declared by

    supprimer_fn cs_supprimer;
    

    and its implementation is defined as before

    void cs_supprimer(conteneur_sommets *cs)
    {
        cs->supprimer(cs->donnees);
    }