我有两个定义的结构,它们都有一个共同的字段。 typedef struct entry entry;
example* example; //malloc and null pointer checking left out
add_entry(&example->list_e, &example->nb_elements, &example->nb_mllc);
我是否有可能编写一个函数,使得mystruct或example可以是一个变量的类型?在该函数中,我填写列表“条目”,所以我知道我可以通过将方法编写为
来完成{{1}}
但是这看起来像是一个肮脏的解决方案,因为我将不得不调用像
这样的函数{{1}}
然后也是mystruct,但我宁愿不将结构的变量拆分为函数参数。是否有可能以某种方式做出相同类型的示例和mystruct,以便我可以将整个结构作为参数
答案 0 :(得分:1)
我是否有可能编写一个函数,使得mystruct或example可以是一个变量的类型?
没有。每个函数参数都只有一种类型。尽管您的两个结构具有相同类型的成员,但顺序相同,名称相同,但由于具有不同的struct
标记,因此它们是不同的,不兼容的类型。 (另一方面,typedefed名称的不同与此目的无关。)接受其中一种类型的参数或指向该类型的指针的函数不能将另一种类型的参数接受到同一参数中。
有人可能会建议将指向其中一种类型的指针作为指向另一种类型的指针,以便能够将其传递给您的假设函数。虽然在实践中可能会产生所需的结果,但它仍然违反了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
,您可以通过一组函数将它们链接到列表中。该类型可以引用(或嵌入,如果您愿意)example
或mystruct
,其中成员is_mystruct
消除了实际存储的歧义。或者,如果从上下文中显示存储的类型,则可以删除is_mystruct
。
答案 1 :(得分:0)
许多实现都允许使用C语言编写的函数调用其他语言编写的函数或由其他语言编写的函数调用。这样的实现通常会详细说明(在称为ABI-Application Binary Interface的文档中)如何在内存中布置各种数据类型,如何将参数传递给函数以及如何传递返回值。除极少数情况外(我什至没有),信息交换的方式完全取决于所涉及类型的实际存储格式,而不取决于这些类型的调用方式。除其他外,struct标签对于这些目的将是不相关的。
在具有记录的ABI的实现中,通过合格的volatile
的函数指针进行的调用基本上总是(*)该ABI所描述的方式。如果ABI不关心结构标记,则在通过易失性函数指针处理调用时,实现也不关心它们。
(*),从理论上讲,实现可以读取易失性函数指针,检查其是否与它所了解的函数匹配,并且仅在指针与任何已知函数不匹配的情况下,才按照ABI的描述进行操作。这种行为将很奇怪,因为实现无法知道volatile
指针可能包含什么,但是“聪明”的实现仍然可以做到。
尽管声明函数指针volatile
有时可能会对性能产生轻微的不利影响,尽管通常不需要这种限定符,但它会减少编译器优化对“预期”函数的调用的可能性。与ABI不一致的方式。