【问题标题】:C equivalent to C++ decltypeC 等价于 C++ decltype
【发布时间】:2018-01-10 07:56:09
【问题描述】:

在我的 C 项目中,有一个结构,由另一位同事创建,包含一些函数指针:

struct tools {  
    int (*tool_a) (int, int, int);
    ...
};

我无权更改此结构和相关文件。

现在我正在使用结构进行编码。
我必须定义一个函数,它的返回类型和参数列表必须与tools.tool_a相同。
这意味着我的功能必须如下:

int my_func(int, int, int);

问题是struct改了很多,尤其是返回类型,比如int今天换成了size_t,所以我的代码要改很多。

我知道 C++ 中的 decltype 可以帮助我,所以我只想知道 C 是否有等价的东西?

我在想我可以使用宏,但我不知道如何,我什至不知道这是否可能。

真实案例

我正在用 C 开发一些用于 linux-kernel 的测试工具。
我公司的其他团队有很多版本的自定义内核。由于历史原因,有的用int,有的用size_tssize_t等等。

现在当我编码时,我必须这样做:

// int my_func(int a, int b, int c)
size_t my_func(int a, int b, int c)
// ssize_t my_func(int a, int b, int c)
{}
struct tools my_tool = {
    .tool_a = my_func;
}

我必须不断评论和取消评论...

【问题讨论】:

  • "我无权更改此结构,但结构变化很大。"这有什么意义?如果人们无论如何都在更改代码,只需强制使用 typedef。
  • 请记住,在 C 中,tools 是一种数据类型,而不是可以在其上使用成员访问运算符的变量。
  • 顺便说一句,尽管您正在寻找与 C++ 等效的工具,但我认为它并不需要 C++ 标签。
  • 所以基本上,您有1..N 组为您提供代码,并且您希望对这些N 代码运行相同的测试。每次从x 组获取代码时,签名都是相同的,但当您从y 组获取代码时,签名可能会有所不同。也许您可以为每个组定义一个唯一的符号并更改您的编译过程以包含此符号,例如make GROUP=x。然后剩下的就是一个预处理器条件,它根据GROUP 值启用不同的函数签名。
  • @Yves 我明白了。然后我想我想出了一个解决方法,请参阅下面的答案。

标签: c++ c macros decltype


【解决方案1】:

明智的解决方案是强制执行typedef。如果这是不可能的,并且函数可能具有的替代类型的数量是有限的,那么您可以使用 C11 _Generic 来做一些事情。

不要创建一个名为my_func 的函数,而是创建多个具有不同名称的函数。根据返回类型为其名称添加前缀。然后有一个宏,该宏又根据传递的类型重定向到适当的函数。

例子:

#include <stdio.h>

/*** the struct that cannot be changed ***/
struct tools {  
    int (*tool_a) (int, int, int);
};

/*** any number of functions with different types ***/
int int_my_func(int a, int b, int c) 
{ 
  puts(__func__); 
}

size_t size_t_my_func(int a, int b, int c) 
{ 
  puts(__func__); 
}

/*** macro to select the appropriate function based on type ***/
#define my_func_typeof(type)                           \
  _Generic( (type),                                    \
            int(*)(int,int,int)    : int_my_func,      \
            size_t(*)(int,int,int) : size_t_my_func)

/*** caller code ***/
int main (void)
{
  struct tools my_tool = {
    .tool_a = my_func_typeof( (struct tools){0}.tool_a )
  };

  my_tool.tool_a(1,2,3);

}

在这里,我使用复合文字 (struct tools){0}.tool_a 创建与 tool_a 相同类型的虚拟对象,然后将其传递给选择适当函数的宏。如果不支持该类型,则会出现编译器错误,因为找不到匹配的 _Generic 关联。

【讨论】:

  • 是的,我总是忘记通用选择。这应该是公认的答案。
  • @StoryTeller 尽管如此,typedef 版本是正确且最正确的版本。像这样的代码是最后的手段。
  • 不错的解决方案。我有点困惑为什么你在宏的函数名中需要##...
  • typedef 会给我们带来什么好处?如果 typedef 的定义不同,函数的定义仍需更改。
  • @Gerhardh 实际上,## 根本不需要,这是我第一次尝试解决这个问题。固定的。关于 typedef,可以先做typedef int func_t (int, int); 然后func_t func;
【解决方案2】:

好吧,这不是decltype,但如果您可以说服您的同事使用类型别名,您就可以进行静态类型检查。

如果可以说服你的同事这样做:

typedef int tool_a_prototype(int, int, int);

struct tools {  
    tool_a_prototype *tool_a;
};

然后你可以像这样声明你的函数:

tool_a_prototype my_tool_a;

int my_tool_a(int a, int b, int c) {
  //Whatever
}

您友好的编译器会告诉您是否存在原型不匹配。

【讨论】:

  • 我重新编辑了我的问题。唔。我马上试试。 :D
  • @Yves - 我希望它有所帮助。但是,我不确定它是否能回答这个问题。您想要类型检查或评论/取消评论的需要消失吗?
  • 没错。我只想停止评论/取消评论。你看我昨天开发了我的工具,今天很多同事都在使用它。但是他们正在测试不同的版本...所以我必须将int 用于第1 组,将size_t 用于第2 组...这真的很无聊...
  • 无论如何,您的回答很有帮助。 :D 至少我可以给我的领导写个报告……
  • @AjayBrahmakshatriya - 我个人认为size_tint 都应该用类型别名来抽象。那么函数的主体将至少只包含对别名的强制转换。无论哪种方式,这都是 OP 所从事的令人讨厌的业务。
【解决方案3】:

问题是struct变化很大,尤其是return 类型,例如 int 今天被 size_t 取代,所以我必须 大量更改我的代码。

我知道 C++ 中的 decltype 可以帮助我,所以我只想知道 C 有什么等价的吗?

如果你愿意使用非标准 gcc 扩展,你可以使用typeof:

struct tools {  
    int (*tool_a) (int, int, int);
};

typedef typeof( ((struct tools*)NULL)->tool_a ) tool_a_type;
typedef typeof( ((tool_a_type)NULL)(0,0,0) ) tool_a_return_type;

tool_a_return_type my_func(int x, int y, int z)
{

}

struct tools my_tool = {
    .tool_a = my_func
};

【讨论】:

    猜你喜欢
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2011-09-19
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多