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 编译器,那么您可以使用 _Generic
在 int*
和 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;
}
我想实现一个函数,该函数将 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 编译器,那么您可以使用 _Generic
在 int*
和 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;
}