【问题标题】:_Generic works with typedef structs or only with primitive types?_Generic 适用于 typedef 结构还是仅适用于原始类型?
【发布时间】:2021-01-08 19:53:54
【问题描述】:

Generic o(X) 用于从多种类型构造 Object。但 GCC 不会扩展到 typedef 类型。

warning: passing argument 1 of ‘oBytes’ from incompatible pointer type [-Wincompatible-pointer-types]
   68 |    Object ovi = o(vi);
      |                   ^~
      |                   |
      |                   HashTable {aka struct _HashTable *}
../cedata.h:13:43: note: in definition of macro ‘o’
   13 |                     char        : oBytes( X , 1),         \
      |   
o(x)的

_Generic定义:

#define o( X )  _Generic ((X),                            \
                        char        : oBytes( X , 1),         \
                        char *      : oNewFrom(STRING, X),    \
             unsigned   char *      : oNewFrom(STRING, X),    \
                        int         : oNewFrom(INT, X),       \
                        float       : oNewFrom(FLOAT, X),     \
                        short       : oNewFrom(SHORT, X),     \
                        HashTable   : oNewFrom(HASHTABLE,X),  \
                        List        : oNewFrom(LIST, X),      \
                        default     : oNew()                  \
                    )

所有 oNewFromoBytes 都返回 Object

vi 哪个类型是HashTable 又名struct _HashTable * 与此泛型一起使用时,在Object ovi = o(vi); 行gcc 调用char : oBytes( X , 1), 而不是HashTable : oNewFrom(HASHTABLE,X),

我犯了任何错误或泛型不适用于结构和类型定义?

【问题讨论】:

  • IIRC,通用选择器中的每个表达式都必须有效并检查错误/警告。
  • 我想STRING 等。人。是类型的枚举。由于_Generic 的限制[正如其他人提到的那样],为什么不对所有类型使用相同的代码? (例如)type : oAny(STRING,&X), int : oAny(INT,&X), ...oAny 是:void *oAny(int type,void *src) 它可以在type 上执行switch 并调用正确的函数(例如oBytesONewFrom 等)。
  • Removing oBytes HashTable 现在扩展为 oNewFrom(HASHTABLE,X) 我重新考虑我的构造函数并发现 char 是不必要的。

标签: c generics typedef c11


【解决方案1】:

遗憾的是,对于_Generic,每个表达式都需要对类型进行编译,而不仅仅是使用的那个。

#define o( X )  _Generic ((X),                            \
                    char        : oBytes( X , 1),         \
                    ...
                    HashTable   : oNewFrom(HASHTABLE,X),  \
                    ...
                )

HashTable vi; ... o(vi) 无法编译,因为oBytes( X , 1)XHashTable 时无法编译,即使未选择该行也是如此。

使用int, void *, double, ...,定义了类型之间的转换。然而,将HashTable 用作struct,缺少与基本类型之间的转换。


我会考虑发布一个替代方案,但 OP 的帖子缺乏开展这项工作的详细信息。

一个典型的替代方法是将X 的地址传递给各个函数。

【讨论】:

    【解决方案2】:

    由于您对每种类型都有定义,因此您可以将调用约定指定为对所有类型都相同。

    例如:

    create_xxx(void *obj);
    //xxx stands for the different types
    

    然后是你的通用宏:

    #define o(X) _Generic((X), \
        type1: create_type1(X), \
        type2: create_type2(X), \
        ...
    

    由于 create 函数的参数是一个不透明的指针,编译器永远不会抱怨你传递给函数的内容。而且您的函数知道如何处理该地址的数据。

    --- 根据您的评论 ---

    由于我不确切知道您要完成什么,我只提供了泛型的基本用法以及如何避免给定警告。

    我的意思的最小可执行代码:

    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct ObjectRec {
        int id;
    } Object;
    
    void* create_int(void *ptr)
    {
        printf("create_int\n");
        return ptr;
    }
    
    void* create_float(void *ptr)
    {
        printf("create_float\n");
        return ptr;
    }
    
    void* create_obj(void *ptr)
    {
        printf("create_obj\n");
        ((Object*) ptr)->id = 0;
        return ptr;
    }
    
    #define o(X) _Generic((X), \
        int*: create_int, \
        float*: create_float, \
        Object*: create_obj \
    )(X)
    
    int main()
    {
        int i = 1;
        float f = 0.5f;
        Object obj;
    
        o(&i);
        o(&f);
        o(&obj);
    
        return EXIT_SUCCESS;
    }
    

    可能(也)感兴趣:

    Generic selection

    【讨论】:

    • 答案部分正确,但帮助我解决了这个错误。目标是 obj * create_xxx( xxx d )create_xxx 返回 Obj 并获得任何类型。与您的建议相反 create_xxx(void *obj); 但是我明白了您的意思。谢谢。
    • _Generics 没用。测试 o(1) ( _Generics ( int ) ) 现在扩展到所有类型。我收到所有类型的警告!
    • 我在回答中添加了一些信息,希望对您有所帮助。
    猜你喜欢
    • 2016-04-27
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 2016-10-15
    • 2017-11-03
    • 2017-11-18
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多