【问题标题】:How can I pass a “Type” as a argument to function in c?如何将“类型”作为参数传递给 c 中的函数?
【发布时间】:2018-10-30 18:54:06
【问题描述】:

我想编写通用函数(例如,获取void** 类型的数组并对这个数组做一些事情的函数)这样这个函数将获取元素的类型(在示例中,它将是数组中任何元素的类型)作为参数。

我可以用 c 做吗?


例如:

我想编写一个函数来获取数组(void** 的类型)并以某种随机方式初始化这个数组。

“以某种随机方式”我的意思是,例如作为参数获取的函数:数组(类型为void**),数组中任何元素的类型,索引(在int) 的类型并初始化此单元格。

【问题讨论】:

  • 我想用 c 编写泛型函数,例如,获取数组的函数(类型为 void**)并对这个数组做一些事情。我想知道我是否可以将此数组中任何元素的类型(例如)传递给函数..
  • 宏可以(某种程度上)做到这一点。 C 在 C++ 中没有模板之类的东西
  • 在一定程度上,你可以使用 C11 的_Generic 来编写泛型函数,但是你几乎必须事先知道所有你想要的类型泛化

标签: c arrays types generic-programming


【解决方案1】:

这只有在你有一个标准的 C 编译器时才有可能,在这种情况下你可以使用 _Generic 关键字来达到这个目的。您必须为每种支持的类型编写不同的函数。

#include <stdio.h>

#define func(x) _Generic((x), int: func_int, char: func_char)(x);

void func_int (int x)
{
  printf("%s\t%d\n", __func__, x);
}

void func_char (char x)
{
  printf("%s\t%c\n", __func__, x);
}


int main(void)
{
  int i = 5;
  char c = 'A';

  func(i);
  func(c);
}

输出:

func_int        5
func_char       A

【讨论】:

  • 你应该添加a reference or two;仅限 C11。 (此外,“标准 C 编译器”基本上没有意义,除非您指定 which 标准。)
  • 不,除非 OP 明确提到另一个 C 版本,否则我们可以假设他们使用的是标准 C。
  • @Lundin 再说一遍,哪个标准?阅读此答案的人完全有可能正在使用 C99 编译器 - 比如说,因为他们所在的学校还没有转向实际的现代编译器,这令人不安地合理 - 如果至少没有指定,这只会浪费他们的时间。
  • @NicHartley ISO 9899。他们只有一个有效的标准。见stackoverflow.com/tags/c/info
  • @Lundin 但是“有效标准”和“使用标准”不一样。就像我说的那样,完全有可能某人被限制在旧版本的 C 中。与将“标准 C”更改为“C11”相比,您浪费了更多的时间来辩论,这很简单、明确且更容易为刚接触 C 的人找出答案。我已经和你讨论完了这个问题;如果您不知道无需额外工作而使某些内容更易于阅读是一件好事,那么我会让您自己弄清楚。
【解决方案2】:

你没有传递“类型”。 C 没有在运行时对类型信息进行编码和解码的内置方法。对对象进行操作的函数必须静态地知道类型。如果您绝对打算使用指向void 的指针,则必须委托给一个知道类型信息的函数。这可以通过回调来完成。例如,标准库函数qsort 接受一个回调来比较对象的值:

void qsort( void *ptr, size_t count, size_t size,
            int (*comp)(const void *, const void *) );

调用代码提供回调,并在所述回调中将其转换回它需要比较的静态类型。这就是人们通常使用指向 void 的指针的方式,以抽象形式定义它需要对类型执行的一组操作,然后要求调用代码提供这些操作的实现。

【讨论】:

    【解决方案3】:

    这是一些宏技巧的示例。

    func.h

    #ifndef FUNC_H
    #define FUNC_H
    
    #define add(a, b, typename) functionAdd##typename(a,b)
    
    /* function declarations */
    #define declared(typename) \
    typename functionAdd##typename(typename, typename)
    
    declared(int);
    declared(float);
    
    #endif
    

    func.c

    #include "func.h"
    
    /* function code */
    #define functionAdd(a, b, typename) \
    typename functionAdd##typename(typename a, typename b){ \
        return a+b; \
    }
    
    /* function bodies (definitions) */
    functionAdd(a, b, int)
    functionAdd(a, b, float)
    

    ma​​in.c

    #include <stdio.h>
    #include "func.h"
    
    int main()
    {
        int x1 = add(1, 2, int);
        float x2 = add(3.0, 4.0, float);
        printf("%d %f\n", x1, x2);  
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      另一种解决方案是定义一个枚举来表示这样的类型:

      #include "stdio.h"
      
      typedef enum {
          TYPE_INT,
          TYPE_CHAR,
          TYPE_STRING
      } type_id;
      
      int print(type_id type, void *data) {
          switch (type) {
          case TYPE_INT:
              // Do something with data as int
              printf("%d\n", * (int *)data);
              break;
          case TYPE_CHAR:
              // Do something with data as char
              printf("%c\n", * (char *)data);
              break;
          case TYPE_STRING:
              // Do something with data as string
              printf("%s\n", (char *)data);
              break;
          }
      }
      
      int main() {
          int a = 5;
          char b = 'a';
          char *c = "string";
      
          print(TYPE_INT, &a);
          print(TYPE_CHAR, &b);
          print(TYPE_STRING, c);
      
          return 0;
      }
      

      我更喜欢 Lundin 的建议,因为它提供了类型安全性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-22
        • 1970-01-01
        • 1970-01-01
        • 2018-12-12
        • 1970-01-01
        • 2020-07-22
        相关资源
        最近更新 更多