C 函数的参数可以是不同的结构

C 函数的参数可以是不同的结构,c,pointers,struct,C,Pointers,Struct,我正在尝试获得一些复杂的功能,我将在这里对其进行简化描述: 我有几种不同变量的结构: struct param1 { int varA; int varB; }p1; struct param2 { int varX; int varY; int varZ; }p2; 另一方面,我有一个函数必须与这些结构一起工作,让我们简化一下,它们只打印数据: void function(int type_of_structure, <<struct param>>) 我

我正在尝试获得一些复杂的功能,我将在这里对其进行简化描述:

我有几种不同变量的结构:

struct param1 {
int varA;
int varB;
}p1;

struct param2 {
int varX;    
int varY;
int varZ;
}p2;
另一方面,我有一个函数必须与这些结构一起工作,让我们简化一下,它们只打印数据:

void function(int type_of_structure, <<struct param>>)
我知道这可以在C中使用带有void**参数和强制转换的函数来完成。然而,我尝试了很多方法却没有成功


我应该如何在函数中声明才能区分不同类型的结构?

使用
联合,这才是真正的方法

#包括
枚举结构类型{
结构类型A,结构类型B
};
结构A{
int x;
int-y;
};
结构B{
int x;
int-y;
intz;
};
工会C{
结构A;
结构B;
};
无效的
打印(枚举结构类型,union C对象)
{
开关(类型){
案例结构类型:
fprintf(stdout,“(x,y)=%d,%d\n”,object.a.x,object.a.y);
打破
案例结构类型:
fprintf(stdout,“(x,y,z)=%d,%d,%d\n”,object.b.x,object.b.y,object.b.z);
打破
}
}
int
主(空)
{
联合C a={.a={1,2}};
联合体cb={.b={3,4,5}};
打印(结构类型A,A);
打印(结构类型B,B);
返回0;
}
对泛型使用
void*
指针在中是非常危险的。而且,它并不意味着要有泛型类型,如果您习惯于考虑泛型,那么处理它是很困难的,但是当您深入理解它时,其他解决方案显然更适合


注意:如果有
int print_struct_a(文件*目标,常量结构a*常量对象),这段代码会更干净
并从
print()
函数中调用它们。

由于您根据“标记”(
type\u of_structure
)识别结构,因此可以使用
void*
并根据标记解释它:

void function(int type_of_structure, void *arg)
{
    switch(type_of_structure)
    {
    case 1: {
    struct param1 *s1 = arg;
    printf("param.varA = %d \n",s1->varA);
    printf("param.varB = %d \n",s1->varB);
    break;
    }

    case 2: {
    struct param2 *s2 = arg;
    printf("param.varX = %d \n",s2->varX);
    printf("param.varY = %d \n",s2->varY);
    printf("param.varZ = %d \n",s2->varZ);
    break;
    }
    }
}
你可以称之为:

function(type_of_structure, &param);

尽可能避免强制用户调用具有正确枚举数和正确匹配对象类型的函数


如果想进入C11
\u Generic
,code可以创建一个宏
DO\u print(X)
,用于选择正确的打印功能<代码>结构的int类型
不需要

否则,我建议代码简单调用特定于结构的打印函数

考虑到结构可能具有任意大小,我建议通过地址传递它们

#include <stdio.h>

typedef struct param1 {
  int varA;
  int varB;
} p1;

typedef struct param2 {
  int varX;
  int varY;
  int varZ;
} p2;

void DO_print_p1(const p1 *o1) {
  printf("param.varA = %d \n",o1->varA);
  printf("param.varB = %d \n",o1->varB);
}

void DO_print_p2(const p2 *o2) {
  printf("param.varX = %d \n",o2->varX);
  printf("param.varY = %d \n",o2->varY);
  printf("param.varZ = %d \n",o2->varZ);
}

#define DO_print(X) _Generic((X), \
  p1 *: DO_print_p1, \
  p2 *: DO_print_p2 \
  )(X)
输出

param.varA = 1 
param.varB = 2 
param.varX = 3 
param.varY = 4 
param.varZ = 5 

如果代码仍然希望使用一个公共的
void函数(int-type\u的\u结构,)
,以便于实现,那么通过包装函数将其隐藏起来,以防用户直接使用/滥用

static void function(int type_of_structure, void *ptr) {
  switch (type_of_structure) {
    case 1: 
      const p1 *o1 = ptr;
      ...
      break;
    case 2: 
      const p2 *o2 = ptr;
      ...
      break;
  }
}

void DO_print_p1(const p1 *o1) {
  function(1, o1);
}

void DO_print_p1(const p2 *o2) {
  function(2, o2);
}

不要那样做。别这样。不要试图强制执行一种可以应用于不同编程语言的概念,这种概念在应用程序中不起作用。当然,您可以实现类似的行为,但是您将拥有一个未定义行为的定时炸弹。此外,在C11中,您可以拥有匿名结构。然后将结构的成员视为联合体的成员,您可以编写
object.x
而不是
object.a.x
。将其封装为
struct D{enum struct_type;union C object}查看一个无处不在的现实世界示例。虽然其他答案是我最初搜索的,但这种使用联合的方法更干净,更有意义。其实我不知道工会的存在!所以我选择这个作为答案,我一直在寻找这样的答案。然而,我发现工会的方法更干净,这就是为什么我会选择另一个答案。不过,您的回答将对我还需要执行的其他任务有所帮助。谢谢
int main() {
  p1 o1 = { 1,2};
  p2 o2 = { 3, 4,5};
  DO_print(&o1);
  DO_print(&o2);
  return 0;
}
param.varA = 1 
param.varB = 2 
param.varX = 3 
param.varY = 4 
param.varZ = 5 
static void function(int type_of_structure, void *ptr) {
  switch (type_of_structure) {
    case 1: 
      const p1 *o1 = ptr;
      ...
      break;
    case 2: 
      const p2 *o2 = ptr;
      ...
      break;
  }
}

void DO_print_p1(const p1 *o1) {
  function(1, o1);
}

void DO_print_p1(const p2 *o2) {
  function(2, o2);
}