如何优雅地实施一系列采用纯C不同类型版本的功能呢? [英] How to elegantly implement a series of functions in different type versions using pure C?

查看:165
本文介绍了如何优雅地实施一系列采用纯C不同类型版本的功能呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写几个功能仅在类型的参数不同。我知道C ++有模板来处理好这个问题(不是很顺利尚未虽然,一些编译器都支持导出关键字,这关键字查询的效率)。对于简单的例子,我想:

I want to write several functions that are only different in the types of arguments. I know C++ has template to handle this problem well (not very well yet though, few compilers support export keyword and this keyword is queried for efficiency). For easy example, I want:

template <typename T>
T add(T a, T b){
    return a+b;
}

然而,在纯C(有时我不得不选择纯C,因为有些平台没有C ++编译器),也必须对不同的版本不同的功能名称,

However, in pure C (sometimes I have to choose pure C, as some platform doesn't have the C++ compiler), there have to be different function names for different versions, as

double addDouble(double a, double b){
    return a+b;
}

int addInt(int a, int b){
    return a+b;
}

嗯,当有两个版本,看来OK,我可以做一个源文件拷贝和粘贴工作;然而,在实践中会有很多行,而不是在一个函数只是一个收益声明,将多个版本。 所以,我的问题是,如何实现不同类型版本一系列功能优雅?

Hmmm, when there are two versions, it seems OK that I can do the copy-and-paste work in a source file; However, in practice there would be many lines instead of just a return statement in a function and would be more versions. So, my question is, how to implement a series of functions in different type versions elegantly?

到目前为止,我已经尝试了一些解决方案如下,但我认为他们是不妙。我需要你的建议,谢谢!

So far I have tried some solutions as below, but I think they are far from good. I need your suggestions, thank you!

解决方案1:

#define mytype int
mytype addInt(mytype a, mytype b){
    return a+b;
}
#undef mytype

#define mytype float
mytype addFloat(mytype a, mytype b){
    return a+b;
}
#undef mytype

解决方案1的缺点:复制的内容太多了,如果我想修改的功能,我要修改所有版本的

Shortcoming of Solution 1: duplicated contents are too many, and if I want to modify the function, I have to modify all of versions.

解决方案2:

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)

的main.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;
}

解决方案2中的缺点:因为函数是写在定义,这是难以调试。此外, \\ 符号是烦人。但是,它的方便的添加一个新的版本,只需插入宣布(双)进入func.h和 functionAdd(A,B,双)进入func.c将实现这一目标。

Shortcoming of Solution 2: Because the function is written in define, it's difficult to debug. Besides, the \ notation is annoying. Though, it's convenient to add a new version, just inserting declared(double) into func.h and functionAdd(a, b, double) into func.c will achieve this aim.

推荐答案

在许多(如果不是大多数)的情况下,模拟C ++用C模板将是最好的办法解决方案3 :参数化的头文件和参数化的实现文件。你的情况,它的工作如下:

In many (if not most) cases the best way to simulate C++ templates in C would be Solution 3: parametrized header file and parametrized implementation file. In your case it would work as follows


  1. 创建元头文件,我们将其命名为 add.dec ,(如下所示)

TYPE_ CONCAT(add, SUFFIX_)(TYPE_ a, TYPE_ b);
TYPE_ CONCAT(sub, SUFFIX_)(TYPE_ a, TYPE_ b);


  • 创建元实现文件,我们将其命名为 add.def ,(如下所示)

    TYPE_ CONCAT(add, SUFFIX_)(TYPE_ a, TYPE_ b){
      return a + b;
    }
    
    TYPE_ CONCAT(sub, SUFFIX_)(TYPE_ a, TYPE_ b){
      return a - b;
    }
    


  • 这两个文件是由两个宏参数化是一个传统的实现宏观级联

    These two files are parametrized by two macros: TYPE_ and SUFFIX_, while CONCAT is a traditional implementation of macro concatenation

    #define CONCAT_(a, b) a##b
    #define CONCAT(a, b) CONCAT_(a, b)
    

    现在,假设你要实例化的模板功能类型 INT 双击。在一个真正的头文件 add.h 你根本

    Now, imagine you want to instantiate your "template" functions for types int and double. In a "real" header file add.h you simply do

    #define TYPE_ int
    #define SUFFIX_ Int
    #include "add.dec"
    #undef TYPE_
    #undef SUFFIX_
    
    #define TYPE_ double
    #define SUFFIX_ Double
    #include "add.dec"
    #undef TYPE_
    #undef SUFFIX_
    

    和一个真实的实现文件 add.c

    and in a "real" implementation file add.c you do

    #define TYPE_ int
    #define SUFFIX_ Int
    #include "add.def"
    #undef TYPE_
    #undef SUFFIX_
    
    #define TYPE_ double
    #define SUFFIX_ Double
    #include "add.def"
    #undef TYPE_
    #undef SUFFIX_
    

    就是这样。通过这样做,你实例化(声明和定义) addInt addDouble subInt subDouble

    当然,你也可以多参数化的声明。您可以添加 DECLSPEC _ 参数可以宣布你sunctions为静态,如果必要的。您可以为参数指定了不同类型和返回值(例如, ARG_TYPE _ RET_TYPE _ )。您可以参数化许多其他的东西。基本上没有限制,你可以参数化的东西。随着一些相当简单的宏技巧,你甚至可以参数化你的函数期望参数的个数。

    Of course, you can parametrize the declarations much more. You can add a DECLSPEC_ parameter to be able to declare your sunctions as static, if necessary. You can specify different types for parameters and return values (say, ARG_TYPE_ and RET_TYPE_). You can parametrize lots of other things. Basically, there's no limit to what you can parametrize. With some fairly easy macro techniques you can even parametrize the number of parameters your functions expect.

    这其实是类似的解决方案1和方案2相结合。这基本上需要从您的两个方法是最好的。而我要说,这是模拟C ++模板实例化的行为,最忠实的尝试。

    This is actually similar to your Solution 1 and Solution 2 combined. This basically takes the best from both of your approaches. And I'd say that this is the most faithful attempt to simulate the behavior of C++ template instantiation.

    请注意每个函数的身体是显式类型只有一次(在你的解决方案1相对于多个明确的副本)。实际的函数体也容易编辑,因为没有必要担心在每行的末尾那些讨厌的 \\ (这是你的解决方案2的情况下)。

    Note that each function's body is explicitly typed only once (as opposed to multiple explicit copies in your Solution 1). The actual function bodies are also easily editable, since there's no need to worry about those pesky \ at the end of each line (as is the case in your Solution 2).

    该方法有另一个有趣的好处:在 add.def 的code将保持可调试,即一个普通的交互式调试器通常是能够进入这些实现(在你的解决方案2是不可能的)。

    This approach has another interesting benefit: the code in add.def will remain "debuggable", i.e. an ordinary interactive debugger will typically be able to step into these implementations (which is impossible in your Solution 2).

    这篇关于如何优雅地实施一系列采用纯C不同类型版本的功能呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆