联盟和普遍功能

时间:2016-01-17 22:55:28

标签: c function unions

我正在尝试用C编写一些库,我有这个联盟:

union { INTEGER, DOUBLE, FLOAT } Types;
typedef struct X {
    Type type;
    union { double a, float b, int c; } val;
    struct X *next;
} MyStruct;

我想要插入功能。例如,它可以是一些结构的插入函数,如树,优先级队列或其他:

insertInt(..., int y), insertFloat(..., float y), insertDouble(..., double y).

通过这种方式,我有很多冗余代码,这是不可取的。另一方面,我们在atoi中有标准字符串转换函数atolatof<stdlib.h>,并且开发库,更好的是重复代码或以某种方式执行它可能与指向void的指针并识别带有类型的类型(在本例中)?

insertInt示例:

MyStruct* insertInt(MyStruct *root, int val) { 
    MyStruct *newNode = (MyStruct*)malloc(sizeof(MyStruct));
    newNode->next = root;
    newNode->val.c = val; 
    newNode->type = INTEGER;
    return newNode;
}

2 个答案:

答案 0 :(得分:1)

您可以使用宏模板来避免源代码重复:

MAKE_INSERT_FUNC(insertDouble, double, a);
MAKE_INSERT_FUNC(insertFloat, float, b);
MAKE_INSERT_FUNC(insertInt, int, c);

以这种方式实例化函数:

MyStruct *insertDouble(MyStruct **root, double val);
MyStruct *insertFloat(MyStruct **root, float val);
MyStruct *insertInt(MyStruct **root, int val);

您仍然需要在头文件中编写声明:

insertXXX()

我更改了API:root函数获取指向列表root指针的指针,因此您无需将返回值存储回原始指针,您可以测试分配是否失败没有破坏现有的清单。

请注意,重复代码(在这种情况下具有较小的变体)比重复源(在进行修改和修复错误时往往变得不一致)要小得多。例如,您可以修改模板以附加新节点,而不是将其添加到ADMINS = ( ('Me', 'me@me.com'), ) MANAGERS = ADMINS DEBUG = False ALLOWED_HOSTS = ['*'] ,并且所有insertXXX函数都将获得新行为。

答案 1 :(得分:0)

这可行吗

#include <stdio.h>
#include <stdlib.h>

enum Type
{
    Integer = sizeof("int"),
    DoublePrecision = sizeof("double"),
    SinglePrecision = sizeof("float")
};

struct GenericNode
{
    enum Type type;
    union
    {
        int _int;
        double _double;
        float _float;
    } value;
    struct GenericNode *left;
    struct GenericNode *right;
};

#define DEFINE_GENERIC_NODE_API_FOR(__type)                                   \
    struct GenericNode *generic_node_create_ ## __type ## _node(__type value) \
    {                                                                         \
        struct GenericNode *element;                                          \
        element = malloc(sizeof(*element));                                   \
        if (element == NULL)                                                  \
            return NULL;                                                      \
        element->left = NULL;                                                 \
        element->right = NULL;                                                \
        element->type = sizeof(#__type);                                      \
        switch (element->type)                                                \
        {                                                                     \
            case Integer:                                                     \
                element->value._int = value;                                  \
                break;                                                        \
            case DoublePrecision:                                             \
                element->value._double = value;                               \
                break;                                                        \
            case SinglePrecision:                                             \
                element->value._float = value;                                \
                break;                                                        \
        }                                                                     \
        return element;                                                       \
    }                                                                         \
                                                                              \
    __type generic_node_get_value_as_ ## __type(struct GenericNode *node)     \
    {                                                                         \
        switch (node->type)                                                   \
        {                                                                     \
            case Integer:                                                     \
                return node->value._int;                                      \
            case DoublePrecision:                                             \
                return node->value._double;                                   \
            case SinglePrecision:                                             \
                return node->value._float;                                    \
        }                                                                     \
        return (__type) 0;                                                    \
    }
DEFINE_GENERIC_NODE_API_FOR(int)
DEFINE_GENERIC_NODE_API_FOR(double)
DEFINE_GENERIC_NODE_API_FOR(float)

int
main(void)
{
    struct GenericNode *node;
    int value;

    node = generic_node_create_int_node(5);
    if (node == NULL)
        return -1;
    value = generic_node_get_value_as_int(node);
    fprintf(stdout, "%d\n", value);
    return 0;
}

这是一个 API 工厂,int有三个字符且double有6和float 5这一事实用于创建枚举(<你可以添加char )和无符号版本。这样可以正常工作,因为它显然是你所需要的,我认为它可能有用。

请注意,您可以根据类型选择 get_value 函数,但是您必须适当地声明目标变量。