共享相同变量的结构的函数指针

function pointer for structures sharing the same variables

我有两个定义的结构,它们都有一个共同的字段。 typedef 结构条目条目;

typedef struct example {
   entry* list_e;
   int nb_elements;
   int nb_mllc;
} example;

typedef struct mystruct {

   entry* list_e;
   int nb_elements;
   int nb_mllc;
} mystruct;

我是否可以编写一个函数,使 mystruct 或 example 可以是一个变量的类型?在那个函数中,我正在填充列表 "entry",所以我知道我可以通过将方法编写为

来做到这一点
 void add_entry(entry** list_e, int* nb, int* nb_mllc){

        //fill the entries
        if (*nb == *nb_mllc) {
           //realloc list_e
        }
}

但是这对我来说看起来像是一个肮脏的解决方案,因为那时我将不得不像

这样调用函数
     example* example; //malloc and null pointer checking left out

     add_entry(&example->list_e, &example->nb_elements, &example->nb_mllc);

然后还有 mystruct,但我宁愿不将结构的变量拆分为函数参数。是否有可能以某种方式使 example 和 mystruct 成为相同的类型,这样我就可以将整个结构作为参数

Is is possible that I write a function such that either mystruct or example can be the type of one variable?

没有。每个函数参数只有一种类型。即使您的两个结构具有相同类型、相同顺序、相同名称的成员,但由于具有不同的 struct 标记,它们是不同的、不兼容的类型。 (另一方面,类型定义名称的差异与此目的无关。)接受其中一种类型的参数或指向该类型的指针的函数不能将另一种类型的参数接受到同一参数中.

可能有人会建议将指向其中一种类型的指针转​​换为指向另一种类型的指针,以便能够将其传递给您假设的函数。尽管在实践中可能会产生预期的结果,但它仍然违反了 C 的严格别名规则,因此会产生未定义的行为。这种行为会让你在积极优化的编译器中遇到麻烦。

您至少有三个选项:

使用相同的结构

从您的问题中看不出为什么您需要不同的类型,因为所讨论的两种类型仅在它们的结构标签上有所不同。如果你简单地选择一个并在任何地方使用它,那么问题就消失了。如果愿意,您可以 typedef 该类型的多个别名;它不会影响您的代码的有效性,您在任何特定地方使用了哪些代码。

嵌入相同结构

这可能是您通过删除实际上不同的两种类型的元素而过度简化了代码。在这种情况下,您可以将包含这些值的通用结构嵌入到更大的结构中,如下所示:

struct list_data {
    entry* list_e;
    int nb_elements;
    int nb_mllc;
};

typedef struct example {
   struct list_data list_data; // must be first
   char *characters;
} example;

typedef struct mystruct {
   struct list_data list_data; // must be first
   int x, y, z;
} mystruct;

C 保证结构的第一个成员的表示将从整个结构表示的第一个字节开始。因此,您可以(原则上)安全地在指向第一个成员的指针和指向整个结构的指针之间来回转换,只要您在后一种情况下小心转换为正确的类型即可。

使用带有鉴别器和联合的节点类型

铸造通常是设计不佳的标志。如果你不能在所有地方都使用相同的类型,那么将嵌入的想法彻底颠覆可能是一个更好的计划:

typedef struct example {
   char *characters;
} example;

typedef struct mystruct {
   int x, y, z;
} mystruct;

struct list_data {
    entry* list_e;
    int nb_elements;
    int nb_mllc;
    _Bool is_mystruct;
    union {
        example *example;
        mystruct *mystruct;
    };
};

现在您有了一个类型 struct list_data,您可以通过一组函数将它们 link 一起放入列表中。该类型可以引用(或嵌入,如果您愿意)examplemystruct,成员 is_mystruct 可以消除实际存储的歧义。或者,如果从上下文中可以明显看出存储了哪种类型,那么您可以删除 is_mystruct.

许多实现允许用 C 编写的函数调用用其他语言编写的函数,或被其他语言编写的函数调用。此类实现通常会详细说明(在称为 ABI--Application Binary Interface 的文档中)各种数据类型如何在内存中布局、如何将参数传递给函数以及如何传递 return 值。几乎没有例外(我知道 none),信息交换的方式完全取决于所涉及类型的实际存储格式,而不取决于这些类型的名称。除其他外,结构标签与此类目的无关。

在具有记录的 ABI 的实现中,通过限定 volatile 的函数指针的调用将基本上始终(*)以该 ABI 描述的方式进行处理。如果 ABI 不关心结构标签,那么在处理通过可变函数指针的调用时,实现也不会关心它们。

(*) 理论上,实现可以读取可变函数指针,检查它是否与它知道的函数匹配,并且仅在指针与任何已知函数不匹配的情况下才按照 ABI 描述的方式运行功能。这种行为会很奇怪,因为实现无法知道 volatile 指针可能包含什么,但 "clever" 实现可能无论如何都会这样做。

虽然声明一个函数指针 volatile 有时可能会对性能产生轻微的不利影响,并且虽然通常不需要这样的限定符,但它会降低编译器优化对 [=22 的调用的可能性=] 以与 ABI 不一致的方式运行。