在函数结构上沉默 WCast-function-type

Silence WCast-function-type on a function structure

我有以下警告:

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

我不知道如何修复此警告。

结构

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;

关联函数

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);
}

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

这个警告意味着两个函数指针的原型不同..

supprimerpile_depiler 具有不同的原型(return 值类型和参数类型)

匹配两个函数的原型,警告就会消失。 简单地说,你可以做原型,但结果是不可预测的。

我已经通过 pragma 宏将其静音

#pragma GCC diagnostic ignored "-Wcast-function-type"

// some affected code

#pragma GCC diagnostic pop

虽然完全抑制警告有时很有用,但通常最好在代码级别修复问题。 这里的问题是您的声明是错误的,这是首先触发警告的原因。 首先避免将 struct/union 的定义和 typedef 别名的声明结合起来。最好把它们分开,这样你就可以在必要时分开声明和定义。

typedef struct conteneur_sommets conteneur_sommets;

这会为 opaque 结构 struct conteneur_sommets 创建别名 conteneur_sommets。这也称为前向声明。前向声明一般放在头文件中。

现在我们可以定义结构了

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 *);
};

这样您就不需要强制转换函数指针并保留类型检查是否具有正确的签名。

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

其次 C 程序员很少意识到的一件事是,可以定义函数原型的 typedef 别名,而不是函数指针,而是直接定义原型。这有时确实可以使代码更具可读性,即使非常不寻常。让我用您的代码举个例子:

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 *);

这声明了五个函数原型类型定义。

结构现在可以声明为

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

您的 cs_supprimer 函数原型可以通过

声明
supprimer_fn cs_supprimer;

其实现定义如前

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