В простом у меня есть ситуация, когда я хотелось бы позволить функции принимать несколько типов указателей. Чтобы проиллюстрировать мою ситуацию, здесь может быть один вариант использования:

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*, но это фактически позволит передать любой тип указателя без ошибки компиляции. Есть ли способ ограничить функцию, чтобы она принимала только определенное подмножество типов указателей?

2
sffc 8 Сен 2016 в 06:05

3 ответа

Лучший ответ

Если вы можете использовать новые функции C11, ключевое слово _Generic может решить вашу проблему:

void myfunction(void *value) {
    // ...
}
#define myfunction(x) myfunction( \
    _Generic((x), char *: (x), int *: (x)) )
2
R.. GitHub STOP HELPING ICE 8 Сен 2016 в 03:54

Вы могли сделать это:

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

Однако такой дизайн упрощает написание кода с ошибками, который компилятор не поймет за вас, поэтому я бы порекомендовал придумать немного другой дизайн (например, помеченные объединения).

0
M.M 8 Сен 2016 в 03:18

Как указал Хоуман, вы можете использовать объединение для выполнения этой работы, однако у вас все еще есть проблема, заключающаяся в том, что вы должны определить тип, который установлен в типе объединения. Вы можете решить эту проблему, используя перечисление для определения типа внутри вашей функции.

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
 }
1
Matheus Nogueira 8 Сен 2016 в 04:28