如何用C编写genric显示函数来显示所有数据类型的void指针?

如何用C编写genric显示函数来显示所有数据类型的void指针?,c,data-structures,stack,C,Data Structures,Stack,我一直在使用void指针来实现使用数组的堆栈。我知道,在显示void指针指向的值之前,我们需要将其转换为合适的数据类型 这是我的堆栈结构 typedef struct { void **arr; // array stack int size; // size of the stack int top; // top most element of the stack int count; // number of elements in the

我一直在使用void指针来实现使用数组的堆栈。我知道,在显示void指针指向的值之前,我们需要将其转换为合适的数据类型

这是我的堆栈结构

typedef struct {
    void **arr;   // array stack
    int size;    // size of the stack
    int top;    // top most element of the stack
    int count; // number of elements in the stack
} stack_T;
假设我有一个int堆栈,堆栈内容->arr的数据类型为int 现在要显示它的内容,我可以简单地编写一个显示

void displayIntStack( stack_T *stack ) { 
    while ( !isEmpty( stack )) {
        printf( "%d ", *( int * )stack -> arr[ stack -> top] );
        pop( stack ); 
    }
}
我可以使用displayIntStack调用它;它将显示int堆栈的内容


如果我想实现更通用的显示函数来显示所有数据类型的堆栈内容,而不需要编写单独的函数。我该怎么做?

嗯,也许是空指针?它将允许您传递指向任何类型的指针;然后只需解析并打印隐藏在指针后面的值

Hmm可能是无效指针?它将允许您传递指向任何类型的指针;然后只需解析并打印隐藏在指针后面的值,一般选择6.5.1.1,页码:56-57:

您可以使用类型泛型表达式:

#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X) 
让我们假设,有以下函数: displayIntStackstack,int,displayFloatStackstack,float,displayCharStackstack,char

然后,我们定义一个函数displayStackstack,在main中键入

#define displayStack(stack,type)  _Generic((type), int: displayIntStack, float: displayFloatStack, char:displayCharStack)(stack,type)

int main() {
displayStack(stack,1); // calls displayIntStack
displayStack(stack,1.2f); // calls displayFloatStack
displayStack(stack,'c'); // calls char:displayCharStack
  
}
另一种方法:使用宏函数

来自,通用选择6.5.1.1,页码:56-57:

您可以使用类型泛型表达式:

#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X) 
让我们假设,有以下函数: displayIntStackstack,int,displayFloatStackstack,float,displayCharStackstack,char

然后,我们定义一个函数displayStackstack,在main中键入

#define displayStack(stack,type)  _Generic((type), int: displayIntStack, float: displayFloatStack, char:displayCharStack)(stack,type)

int main() {
displayStack(stack,1); // calls displayIntStack
displayStack(stack,1.2f); // calls displayFloatStack
displayStack(stack,'c'); // calls char:displayCharStack
  
}
另一种方法:使用宏函数

如果我想实现更通用的显示函数来显示所有数据类型的堆栈内容,而不需要编写单独的函数。我该怎么做

向堆栈添加一个成员,该成员是执行打印的函数指针。在定义堆栈实例时设置.print成员

typedef struct {
    void **arr;
    int size;
    int top;
    int count;
    int (*print)(void *);
} stack_T;

while (!isEmpty(stack)) {
   stack->print(stack->arr[stack->top]);
   pop(stack); 
}
您可以为int、double和the提供一组预定义的.print函数。这种方法允许用户为任何类型创建自定义打印函数

我还希望有一种方法可以应用它。在不更改堆栈的情况下打印到堆栈

进一步:我认为最好的方法是为堆栈类型形成一个apply函数,而不需要.print函数成员:

伪码

int stack_apply(const stack_T *st, int (*f)(void *state, void *data), void *state) {
  for each node i in the stack
    int result = f(state, stack->arr[i]);
    if (result) return result;
  }
  return 0;
}
现在,当您要打印时:

stack_apply(st, my_print_function, my_print_state);
或者是一个搜索函数,或者是一个最大值函数,或者是一个标准偏差函数

如果我想实现更通用的显示函数来显示所有数据类型的堆栈内容,而不需要编写单独的函数。我该怎么做

向堆栈添加一个成员,该成员是执行打印的函数指针。在定义堆栈实例时设置.print成员

typedef struct {
    void **arr;
    int size;
    int top;
    int count;
    int (*print)(void *);
} stack_T;

while (!isEmpty(stack)) {
   stack->print(stack->arr[stack->top]);
   pop(stack); 
}
您可以为int、double和the提供一组预定义的.print函数。这种方法允许用户为任何类型创建自定义打印函数

我还希望有一种方法可以应用它。在不更改堆栈的情况下打印到堆栈

进一步:我认为最好的方法是为堆栈类型形成一个apply函数,而不需要.print函数成员:

伪码

int stack_apply(const stack_T *st, int (*f)(void *state, void *data), void *state) {
  for each node i in the stack
    int result = f(state, stack->arr[i]);
    if (result) return result;
  }
  return 0;
}
现在,当您要打印时:

stack_apply(st, my_print_function, my_print_state);
或者是一个搜索函数,或者是一个最大值函数,或者是一个标准偏差函数

如何用C编写一个通用的显示函数来显示所有数据类型的void指针

除非为显示函数提供某种显示值的方式,否则无法可靠地执行此操作。主要是因为C类型在运行时是未知的:相同的位序列可能是一个char*字符串或一些double-s数组,甚至可能是在某个并集内。可以考虑学习一种更严格、更安全的类型系统,并在运行时保留一些类型信息。 顺便说一句,您可以在通用堆栈中存储和指向的值。然后,您可以通过使用来减少一个间接的操作,这会带来一些编码方面的麻烦。在某些情况下,由于您的支持,这可能更有效

一种可能是将A传递给显示函数。例如,您可以将一个函数指针作为参数传递,该指针显示指向的值

首先声明签名的可读性

 typedef void element_display_sigt (void*displayed_data);
然后声明显示函数以获取这样的函数指针

 void display_stack(stack_T *stack, element_display_sigt*dispfun);
事实上,你的梦想是什么。它们在C17中不存在。通过阅读C标准草案和

在实践中,元素显示通常需要额外的参数,例如要写入的文件*。你的display_堆栈也会有这个额外的参数

FWIW,闭包存在,也存在于、在、在、在、在Ocaml、在、在中。我听说未来的C标准可能会在C中添加匿名函数

<>你可以考虑在C.

中编码的应用程序中嵌入一个类似的解释器或一个漂亮的方案实现。 你可能对re感兴趣 在……上下左右

如果您为Linux编写代码,请注意和:在某些情况下,可能值得在运行时生成某些代码的C代码,然后将该代码编译为,然后在运行时使用该dlopen ed插件或共享对象。我的例子表明,这可以做上千次。另一种可能是使用机器代码生成库,如或

还应注意,到2020年底,具体而言,仍然有一种

另一种方法是在构建时生成一些打印C代码,工具的灵感来自于。您可以编写自己的生成打印代码,也可以使用编写自己的C代码生成器

如何用C编写一个通用的显示函数来显示所有数据类型的void指针

除非为显示函数提供某种显示值的方式,否则无法可靠地执行此操作。主要是因为C类型在运行时是未知的:相同的位序列可能是一个char*字符串或一些double-s数组,甚至可能是在某个并集内。可以考虑学习一种更严格、更安全的类型系统,并在运行时保留一些类型信息。 顺便说一句,您可以在通用堆栈中存储和指向的值。然后,您可以通过使用来减少一个间接的操作,这会带来一些编码方面的麻烦。在某些情况下,由于您的支持,这可能更有效

一种可能是将A传递给显示函数。例如,您可以将一个函数指针作为参数传递,该指针显示指向的值

首先声明签名的可读性

 typedef void element_display_sigt (void*displayed_data);
然后声明显示函数以获取这样的函数指针

 void display_stack(stack_T *stack, element_display_sigt*dispfun);
事实上,你的梦想是什么。它们在C17中不存在。通过阅读C标准草案和

在实践中,元素显示通常需要额外的参数,例如要写入的文件*。你的display_堆栈也会有这个额外的参数

FWIW,闭包存在,也存在于、在、在、在、在Ocaml、在、在中。我听说未来的C标准可能会在C中添加匿名函数

<>你可以考虑在C.

中编码的应用程序中嵌入一个类似的解释器或一个漂亮的方案实现。 您可能对阅读、关于和关于感兴趣

如果您为Linux编写代码,请注意和:在某些情况下,可能值得在运行时生成某些代码的C代码,然后将该代码编译为,然后在运行时使用该dlopen ed插件或共享对象。我的例子表明,这可以做上千次。另一种可能是使用机器代码生成库,如或

还应注意,到2020年底,具体而言,仍然有一种


另一种方法是在构建时生成一些打印C代码,工具的灵感来自于。您可以编写自己的生成打印代码,也可以使用编写自己的C代码生成器。

不,空白指针指向不完整的类型,直到强制转换为止。没用。我同意@DavidC.Rankin。我认为那不行!不,在强制转换之前,一个空指针指向一个不完整的类型。没用。我同意@DavidC.Rankin。我认为那不行!在C11之前,没有任何事情可以做你正在尝试的事情。C11引入了_Generic宏,该宏在一定程度上允许声明用于处理提供定义的每种类型的选项。除此之外,C型C++中没有这种类型的重载或演绎。这里有一个关于_Generic的讨论的链接。考虑到它的使用笨拙,我从来没有发现过很多有用的东西……当我从C开始时,我总是在想为什么会有人需要C++?!C让我觉得一切都很幼稚。我现在知道为什么了。我想我会使用C++来做任何你需要的,而且,C++可以做你需要更快的开发来避免编写额外的代码,但是代价是编译时的复杂性、内存使用和开销。不要误会我,C++容器中有很多异常和超载——但是Linux内核是用C编写的:直到C11没有任何东西可以做你正在尝试的事情。C11引入了_Generic宏,该宏在一定程度上允许声明用于处理提供定义的每种类型的选项。除此之外,C型C++中没有这种类型的重载或演绎。这里有一个关于_Generic的讨论的链接。考虑到它的使用笨拙,我从来没有发现过很多有用的东西……当我从C开始时,我总是在想为什么会有人需要C++?!C让我觉得一切都很幼稚。我现在知道为什么了。我想我会使用C++来做任何你需要的,而且,C++可以做你需要更快的开发来避免编写额外的代码,但是代价是编译时的复杂性、内存使用和开销。别误会,有很多人
是在C++容器和重载中的,但是Linux内核是用C编写的:是的,但是你仍然需要写DISPLAN栈和DISPLAYPROFACTACK和DISPACKARSTACK.但是这个方法很接近我所说的解决方案think@DavidC.Rankin你觉得第二种方法怎么样,我提到了这一点,但缺点是你最终会得到整个堆栈或任何你正在使用的数据结构作为宏而不是代码来编写。这带来了宏的所有固有限制和名称冲突_泛型适用于泛型看跌期权等简单的事情。。当您试图将复杂的数据处理变得通用时,确实会遇到一些限制。这有点像一个圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠。如果你看Linux内核代码——很多看起来都是这样的:是的,但关键是你仍然需要编写displayIntStack、displayFloatStack和displayCharStack.Agree。但是这个方法很接近我所说的解决方案think@DavidC.Rankin你觉得第二种方法怎么样,我提到了这一点,但缺点是你最终会得到整个堆栈或任何你正在使用的数据结构作为宏而不是代码来编写。这带来了宏的所有固有限制和名称冲突_泛型适用于泛型看跌期权等简单的事情。。当您试图将复杂的数据处理变得通用时,确实会遇到一些限制。这有点像一个圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠圆珠。如果你看一下Linux内核代码——很多看起来都是这样的:这真的很有帮助。谢谢你的回答!这真的很有帮助。谢谢你的回答!