您可以允许几种类型的指针中的一种作为不带 void* 的参数吗?

Can you allow one of a few types of pointers as an argument without void*?

简而言之,我有一种情况想要允许一个函数接受多种类型的指针。为了说明我的情况,这里可能是一个用例:

void myfunction([int* or char*] value) {
    *value = 0xdd;  // safe since value is at least as big as a char*
}

还有一个:

#define MAGIC 0xabcdef0
typedef struct {
    int magic;
    char* content;
} MyStruct;

void myfunction([int* or MyStruct*] value) {
    if (*value != MAGIC) {
        printf("Got an int\n");
    } else {
        printf("Got a MyStruct\n");
    }
}

// example:
int input1 = 0;
MyStruct input2 = { MAGIC, "hello world" };
myfunction(input1);  // "Got an int"
myfunction(input2);  // "Got a MyStruct"

这两种情况都可以使用 void* 参数类型来实现,但这实际上允许传入任何类型的指针而不会出现编译错误。有没有办法限制函数只接受指针类型的特定子集?

不行,先用void*再投

有人可能认为我可以使用 void* 然后检查函数内部的转换,如果不是预期的类型,则引发错误,但不,你也不能这样做,因为 void* loses all its type information.

该死的,我在洗澡前才写。我无法抗拒! BRB :) -- 好的,事实证明 R.. 来自 future 的答案是正确的! ;)

你可以这样做:

void myfunction(void *s)
{
    if ( *(int *)s == MAGIC )
    {
        MyStruct *p = s;
        printf("%s\n", p->content);
    }
}

然而,这种设计使得编写编译器不会为您捕获的错误代码变得容易,因此我建议提出一个稍微不同的设计(例如标记联合)。

正如 Houman 指出的那样,您可以使用联合来完成这项工作,但是,您仍然有一个问题,即您必须识别在联合类型中设置的类型。您可以使用枚举来识别函数内的类型来解决这个问题。

union myUnion {
    int* intPointer,
    MyStruct* myStructPointer
};

enum typeEnum {
    INT,
    MYSTRUCT
};

void myfunction(union myUnion union, enum typeEnum type) {
    if (type == INT)
         // you got an integer
    else if (type == MYSTRUCT)
         // you got a struct
    // You can add future additions here
 }

如果您可以使用 C11 中的新功能,_Generic 关键字可以解决您的问题:

void myfunction(void *value) {
    // ...
}
#define myfunction(x) myfunction( \
    _Generic((x), char *: (x), int *: (x)) )