【问题标题】:C getting type of a pointerC获取指针的类型
【发布时间】:2022-01-12 16:04:29
【问题描述】:

我想实现一个函数,它将 int 或 char 指针作为输入,然后存储为 void 指针,但我也想存储已传递的指针的类型,所以有什么方法可以找到指针的类型

【问题讨论】:

  • 使用布尔值判断是int*还是char*
  • 听起来像是 union 的工作?
  • @CherryDT 它是 C,而不是 C++。
  • @BernardoDuarte 一个带有标志字段和两个指针联合字段的结构?
  • @procoder35 底线是,如果你只有一个 void * 类型的指针值,则无法判断它最初是一个 int 指针还是一个 char 指针(或其他别的)。您必须以其他方式明确地、自己地跟踪这些信息。

标签: c pointers void-pointers


【解决方案1】:

我想实现一个以 int 或 char 指针作为输入的函数

你不能。您可以实现接受 void 指针的函数,或接受包含 int 指针和 char 指针成员的联合的函数,或接受 int 指针 char 指针作为单独参数的函数,或两个函数,一个接受一个 int 指针,另一个接受一个 char 指针,但您不能实现一个接受通过同一参数选择 int 指针或 char 指针的函数。这两种指针类型不兼容。

如果您选择 void 指针参数,那么您将从任何对象指针类型(不仅仅是 int 指针和 char 指针)到 void 指针的隐式转换中受益,但这只会移动您实际问题的轨迹:

然后将其存储为 void 指针,但我还想存储已传递的指针的类型,所以有没有办法可以找到指针的类型

如果将一种类型的指针转​​换为不同的指针类型,则结果不包含有关原始类型的任何信息。如果你想要这样的信息,那么你需要单独传送和存储它。使用 void 指针选项,这将意味着您的函数的另一个参数传达附加信息。每个可用选项都需要某种形式。

【讨论】:

    【解决方案2】:

    如果您使用的是符合 C11 的编译器,则可以使用 _Generic 宏对类型进行排序重载,但类型必须单独存储,无论是 void* 还是带有某种标记的联合。

    最接近你想要的东西是这样的:

    #include <stdio.h>
    #include <assert.h>
    
    struct TaggedUnion
    {
        void* contents;
        /* union {int* i;char* c;} contents; */
    
        enum Type {CHAR_TYPE, INT_TYPE} type;
    };
    
    struct TaggedUnion storeI(int* x)
    {
        struct TaggedUnion ret = {.contents =x, .type=INT_TYPE};
        return ret;
    }
    
    struct TaggedUnion storeC(char* x)
    {
        struct TaggedUnion ret = {.contents =x, .type=CHAR_TYPE};
        return ret;
    }
    
    #define storeTagged(x) _Generic((x),\
        int*: storeI,\
        char*: storeC)(x)
    
    int* getInt(const struct TaggedUnion x)
    {
        return x.type == INT_TYPE ? x.contents : NULL;
    } 
    
    char* getChar(const struct TaggedUnion x)
    {
        return x.type == CHAR_TYPE ? x.contents : NULL;
    } 
    
    void fi(int* arg)
    {
        printf("i\n");
    }
    
    void fc(char* arg)
    {
        printf("c\n");
    }
    
    
    #define ff(x) _Generic((x),\
        int*: fi,\
        char*: fc)(x)
    
    int main(int argc, const char* argv[])
    {
        printf("entry\n");
        int* i;
        char* c;
    
        ff(i);
        ff(c);
    
        struct TaggedUnion ti = storeTagged(i);
        struct TaggedUnion tc = storeTagged(c);
    
        assert(ti.type == INT_TYPE);
        assert(tc.type == CHAR_TYPE);
    
        return 0;
    }
    

    https://godbolt.org/z/5dcrc84fo

    【讨论】:

    • 非常感谢您的努力。谢谢:>
    【解决方案3】:

    如果您使用的是 C11 编译器,则可以使用 _Genericint*char* 之间分派类型标识符。

    typedef enum {
      VT_INT,
      VT_CHAR,
    } void_type_id;
    
    typedef struct {
      void_type_id id;
      void *ptr;
    } void_typed;
    
    void_typed make_void_typed_impl(void_type_id id, void* ptr) {
      return (void_typed) { .id = id, ptr = ptr };
    }
    
    // returns type id from the pointer type
    #define vt_id(ptr) _Generic((ptr), char*: VT_CHAR, int*:  VT_INT)
    #define make_void_typed(ptr) \
      make_void_typed_impl(vt_id(ptr), ptr)
    

    示例用法:

    #include <stdio.h>
    
    int main() {
        char *c_ptr = 0;
        int *i_ptr = 0;
       void_typed vc = make_void_typed(c_ptr);
       void_typed vi = make_void_typed(i_ptr);
    
       printf("vc=(%d, %p)\n", (int)vc.id, vc.ptr);
       printf("vi=(%d, %p)\n", (int)vi.id, vc.ptr);
    }
    

    打印:

    vc=(1, (nil))
    vi=(0, (nil))
    

    此解决方案可以轻松扩展以支持其他类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多