【问题标题】:How can I create a function that takes a parameter of unknown type in C?如何在 C 中创建一个接受未知类型参数的函数?
【发布时间】:2011-08-27 02:20:55
【问题描述】:

假设我有以下代码:

struct test* t1;
t1 = get_t(1);

...get_t 是:

struct test* get_t(int);

如何重构上述代码并将其放入函数中?类似于以下内容:

void r1(?* t, ?* (fn*)(int)) {
    t = fn(1);
}

/* ... */

struct test* t1;
r1(t1, &get_t);

【问题讨论】:

  • 你可以使用void r1(struct test* t, struct test* (fn*)(int))...为什么是未知类型的参数?
  • 因为我想为struct another_test 使用相同的函数。就像我拥有struct test* t1 并使用r1(t1, &get_t) 一样,我也希望能够拥有struct another_test* t2 并使用r1(t2, &get_at),其中get_at 返回struct another_test*,并执行相同的操作来获取它。跨度>

标签: c types


【解决方案1】:

使用void *param,一个指向任何东西的指针......在glib中常用为gpointer

【讨论】:

  • 如果我将r1 定义为void r1(void* t, void* (fn*)(int)),那么编译器会抱怨我没有给它正确的函数,因为我的get_t 函数返回一个struct test*
  • get_t 也需要返回void *
  • @rdineiu:您还需要适当地更改您的 get_t 函数。签名需要更改,但您的实现可能会假定参数是您需要的类型。
  • 啊哈,所以唯一的办法就是让get_t返回void*?
  • Void 指针确实是用 C 编写完整的通用代码的唯一方法。还应该注意的是,您真正需要编写此类通用代码的唯一情况是在设计抽象代码模块时,例如作为 ADT 和搜索/排序算法。如果您发现自己在任何其他情况下都需要完全通用的代码,您可能应该重新考虑您的程序设计。
【解决方案2】:

我有两个想法:

[1] 将void 指针传递给变量/对象,并在函数中进行类型转换。

[2] 将所有数据类型与一个整数数据类型结合起来,该数据类型将识别联合中的哪个数据类型变量确实保存了实际数据。将此联合作为值或void *

struct _unknown {
   union {
      int a;
      float b;
      char c;
      double d;
   } data;
   int type;
} unknown;
.
.
.
if (unknown.type == FLOAT)
{
  /* Process variable b */ 
}
else if (unknown.type == INT)
{
 /* Process variable a */
}
.
. 
.

类似的东西。

您可以散列将FLOATINT 等定义为唯一值。

或者干脆

struct _unknown {
  void *data;
  int type;
} unknown;
.
.
.
if (unknown == FLOAT)
{
  /* process (float *) data */
}
else if (unknown == INT)
{
  /* process (int *) data */
}
else if (unknown == MY_DATA_TYPE)
{
  /* process (my_data_type *) data */
  /* where my_data_type could be a typedef, or struct */
}

【讨论】:

    【解决方案3】:

    如果你有 gcc,你可以使用这个更安全的版本:

    #define r1(varp,func) ({ \
        typeof(**varp)* (*_func_)(int); \
        typeof(**varp)* _varp_ = (varp); \
        _func_ = (func); \
        r1_((void**)(_varp_),(void*(*)(int))_func_); \
        })
    
    void r1_(void** varp,void*(*func)(int))
        {
        *varp = func(1);
        }
    

    调用为:

    struct test* get_t(int);
    struct test* t1;
    r1(&t,get_t);
    

    (您不需要在函数上使用&,它们会自动衰减为指针,就像数组一样)。这将检查 t 是一个指针,并且 get_t 是一个返回该类型指针的函数。 _varp_ 在技术上是不需要的,但会以正确的顺序保持参数评估。

    编辑:

    如果你没有 gcc,你仍然可以这样做,但你必须明确提供类型:

    #define r1(T,varp,func) do { \
        T*(*_func_)(int); \
        T* _varp_ = (varp); \
        _func_ = (func); \
        r1_((void**)(_varp_),(void*(*)(int))_func_); \
        } while(0)
    
    void r1_(void** varp,void*(*func)(int))
        {
        *varp = func(1);
        }
    

    调用为:

    struct test* get_t(int);
    struct test* t1;
    r1(struct test*,&t,get_t);
    

    不那么安全,而且更多余,但仍然相当不错。

    【讨论】:

      猜你喜欢
      • 2013-07-14
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      • 2015-01-22
      • 2012-09-08
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多