动态访问结构的成员变量

时间:2014-04-29 06:47:54

标签: c pointers data-structures function-pointers

我有不同的结构,我想编写一个通用框架来获取一个排序的元素列表来自一个哈希表或C中这些结构的列表。例如,如果我有一个结构定义

struct XYZ{ 
 int a;
 char b[20];
 long time;
}

假设我有一个这种结构类型的元素列表。我需要有一个功能,通过该功能,我可以按结构的任何字段对该列表进行排序,该字段将由用户给出。这种用例也必须可用于其他此类结构,因此这种排序框架应该是通用的。我正在考虑使用一些脚本以不同的自动生成结构的形式存储与此结构相关的不同元数据。该元数据将存储与给定结构中的每个元素相关的信息。此信息将包括结构的类型(即整数,字符串或日期:执行排序操作时不同的类型)以及在结构中访问此元素的方法。现在我的问题是理想情况下应该如何访问这些元素。一种直接的方法是为这些中的每一个生成一些getter函数,并在自动生成的元数据结构中设置getter函数的函数指针。但是使用getter函数来访问每个成员元素意味着每个元素访问的函数调用。这会阻碍应用程序的性能吗?有没有其他办法可以做到这一点?任何其他实现所需用例的框架思想也欢迎。

2 个答案:

答案 0 :(得分:1)

正如评论所建议的那样,最简单的方法是对结构的每个成员使用qsort和回调。
可以使用offsetof宏来创建更通用的单个回调。

单个回调的危险在于,只要结构发生变化,就必须更改函数。它还需要您创建一个全局变量,这也是不理想的。当然,如果你使用单独的回调,你也必须创建一个新的函数。但是,您没有全局,忘记创建新函数更容易调试和修复。

但是作为一个例子,这是一个通用qsort回调的可能方法:

#include <stddef.h>

static size_t member_offset;

int struct_cmp(const void *a, const void *b)
{
    switch(member_offset)
    {
         case 0://or case offsetof(struct XYZ, a):
             return ((struct XYZ *)a)->a - ((struct XYZ *) b)->a;
         case offsetof(struct XYZ, b):
             return strcmp(
                 ((struct XYZ *)a)->b,
                 ((struct XYZ *)b)->b
             );
         case offsetof(struct XYZ, c):
             return ((struct XYZ *)a)->c - ((struct XYZ *) b)->c;
         default:
             fprintf(stderr, "Invalid offset value %d\n", member_offset);
             exit( EXIT_FAILURE );//possible bug
    }
}

int main ( void )
{
    struct XYZ foo[10];//create array of structs
    size_t offsets[3] = { 0, offsetof(struct XYZ, b), offsetof(struct XYZ, c)};
    for (int i=0;i<3;++i)
    {
        member_offset = offsets[i];//omit this, and you're in trouble!
        qsort(
            foo,
            sizeof foo,
            sizeof *foo,
            struct_cmp
        );
    }
    return 0;
}

正如您已经看到的那样,如果结构有10个成员字段,那么回调将看起来像一个邪恶的混乱。由于使用全局变量,它也必然更容易受到攻击。不初始化全局变量,或在另一个线程正在排序时更改全局变量的状态...
老实说:只需为每个成员添加一个函数,但也许可以创建一个函数来保持qsort调用:

void sort_structs(struct XYZ *structs[], size_t count, size_t member_offset)
{//Pass POINTER to array
    switch (member_offset)
    {
        case 0://same cases as above:
            qsort(
                *structs,
                count,
                sizeof *structs[0],//or **structs
                a_sort_callback
            );
            break;
        case offsetof( struct XYZ, b):
            qsort(
                *structs,
                count,
                sizeof *structs[0],
                b_sort_callback
            );
            break;
        case offsetof( struct XYZ, c):
            qsort(
                *structs,
                count,
                sizeof *structs[0],
                c_sort_callback
            );
            break;
        default:
            fprintf(
                stderr,
                "Either %d is invalid offset, or you haven't implemented a callback"
                member_offset
            );
            exit( EXIT_FAILURE );
    }
}

答案 1 :(得分:0)

作为Joachim Pileborg pointed out,C标准库中有一个名为qsort()的函数。您可以将它用于您的目的。但是你必须知道你拥有什么类型的数组并为它们使用适当的排序函数。

如果出于任何原因,您希望对不同的结构类型进行排序(如果通过指针进行排序,那将会有效),它们中的每一个都应该提供一个关键函数来提取您想要排序的值。

如果这样做,您可以在C中有效地构建OOP框架。

但更好的方法是拥有一个统一的数组,并为每个要排序的类型提供一个排序函数。