【问题标题】:Declare generic variable type声明泛型变量类型
【发布时间】:2015-07-10 18:39:11
【问题描述】:

我正在尝试在 C 中声明一个泛型变量类型(我不能使用 C++),我想到了以下选项。

选项1

typedef struct 
{
     void *value;
     ElementType_e type;
} Data_t;

选项 2

typedef struct {
    ElementType_e type;
    union {
        int a; 
        float b; 
        char c;
    } my_union;
} my_struct;

其中 ElementType_e 是一个枚举,它包含所有可能的变量类型(例如 int、char、unsigned int 等)。我有点倾向于选项 1,因为与 switch 相比,我不相信强制转换会增加额外的计算时间,对吧?

我只是想知道哪种类型更有用?我知道选项 1 每次使用/访问时都需要强制转换。强制转换是否可能发生任何问题(尤其是在不同平台上运行/编译代码时,例如 32 位和 16 位微)

而 option2 需要一个 switch () 来执行任何操作(例如添加,...)。

以下链接解释了选项 2 更好(从可读性的角度来看),但我主要关心代码大小和计算成本。 Generic data type in C [ void * ]

【问题讨论】:

    标签: c


    【解决方案1】:

    是否有任何可能发生的问题与铸造

    不,因为您不想强制转换,因为从/到void-指针(在 C 中)分配时不需要强制转换。

    我只是想知道哪种类型更有用?

    两者都有,所以视情况而定

    • 1 适合懒人(因为它的输入很少,而且需要记住的变量名称也很少)。
    • 2 用于谨慎(因为它是类型保存,而不是选项 1,其中“真实”类型信息丢失,因此您甚至可以分配不在 ElementType_e 中的类型的变量地址)。

    引用comment:

    关于性能,我预计这两种方法之间没有重大区别(如果实施得当),因为这两个选项都需要有条件的关于分配给/来自的语句(这里的例外是指针变量,对于选项 1,它没有用于分配的条件语句)。

    【讨论】:

    • 在对 void 指针进行算术运算时需要进行类型转换,对吧?您假设编译器(/运行时)知道指针设置为什么类型的对象,并执行操作,这是不正确的。当您说第二个选项是出于谨慎考虑时,它会增加更多的计算时间?
    • @rasred2004:“你假设编译器(/运行时)知道指针的对象类型”不,我不知道。我假设在应用任何操作之前,void-pointer 的值已分配给指向 ElementType_e 描述的类型的指针的实例。
    • 你能解释更多吗?通过“我假设 void-pointer 的值被分配给指向 ElementType_e 描述的类型的指针的实例”,您已经将其 type_cast 为正确的变量类型了吗?或者您的意思是您可以执行以下操作 (*a_ptr++) + (*b_ptr++),a_ptr 和 b_ptr 是 void 指针。你能举个例子吗?顺便说一句:我喜欢两种方法之间没有区别的想法(从计算成本来看)。
    • @rasred2004:根据您的评论,您不能对void* 执行此操作,不。选项 1 和选项 2 需要某种条件语句来分配给/来自“一般”变量。无论您使用一个选项还是另一个选项,都可以被视为整体问题的实施细节。只需为某些类型实现这两种方法,您就会看到最终结果,然后理解我的意思...... ;-) 无论如何,这是一个很好的练习,你不会失去任何东西。
    • 再说一遍:我不需要演员来做这件事。 int a = 1, b, *pi; void * pv = &a; pi = pv; b = *pi; 此代码将a 的值分配给b。
    【解决方案2】:

    我建议使用联合。事实上,我自己也用过类似的情况:

    union sockaddr_u {
        struct sockaddr_storage ss;
        struct sockaddr_in sin;
        struct sockaddr_in6 sin6;
    };
    

    我在可以使用 IPv4 或 IPv6 地址的套接字代码中使用此联合。在这种特殊情况下,“类型”字段实际上是每个内部结构(ss.ss_family、sin.sin_family 和 sin6.sin6_family)中的第一个字段。

    【讨论】:

    • 这是一个很好的例子,您是否将使用 union 与其他选项的结果进行了比较?
    • 我在建立这个联盟时没有考虑使用其他选项。我更喜欢这种方式,因为我不需要担心额外的内存分配,而且我可以轻松地将指向此联合的指针传递给任何需要 struct sockaddr 或相关结构的函数。它还利用类型系统来验证您传递的内容是您所期望的,而 void * 是无法获得的。
    【解决方案3】:

    我认为问题不是很好,因为程序员可以定义无限可能的数据类型。例如,考虑以下序列:

    typedef char S0_t;
    typedef struct { S0_t x; } S1_t;
    typedef struct { S1_t x; } S2_t;
    typedef struct { S2_t x; } S3_t;
    

    很明显,可以无限地遵循以定义尽可能多的新类型。
    因此,没有直接的方式来处理这种可能性。

    另一方面,由于指针具有更灵活的性质,您可以决定定义只与指针类型相关的泛型类型。
    因此,项目中使用的类型只能是指针。
    这样,可能像下面的定义这样非常简单的东西就可以工作:

     typedef void* generic_t;
    

    【讨论】:

      猜你喜欢
      • 2011-09-28
      • 1970-01-01
      • 2018-02-20
      • 1970-01-01
      • 2015-12-14
      • 2018-12-14
      • 1970-01-01
      • 2019-04-02
      • 2010-10-23
      相关资源
      最近更新 更多