C获取指针类型

C getting type of a pointer

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

I want to implement a function that takes either int or a char pointer as the input

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

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

and stores then as a void pointer but I also want to store the type of the pointer that has been passed so is there a way that I could find the type of the pointer

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

如果您使用的是 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))

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

如果您使用的是 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