Объявление пустых указателей, чтобы подтолкнуть обработку типа вниз по течению - PullRequest
2 голосов
/ 01 октября 2019

Это когда-либо обычно делают что-то вроде следующего:

void *x = (void *) "one";
void *y = (void *) 2;
void *z = (void *) NULL;

Вместо:

char * x = "one";
int y = 2;

Моя причина, по которой я спрашиваю это, заключается в способности вызывать функцию, которая может приниматьнесколько типов. Например, конкат различных элементов, таких как, доступен в javascript. Похоже, что использование (void *) - это просто простой способ обозначить «любой тип».

Ответы [ 2 ]

1 голос
/ 01 октября 2019

Обычно не очень хорошая идея писать функции, которые принимают любой аргумент. Как отмечено в комментариях, вы теряете проверку, обеспечиваемую компилятором.

Однако, есть некоторые случаи, когда вы можете рассмотреть это с помощью 'void *', которые (обычно) считаются приемлемыми:(1) функции varargs и (2) обратный вызов. Важно подчеркнуть, что лучше по возможности рассмотреть альтернативную реализацию.

Функции varargs - это такие функции, как 'printf', 'scanf' и т. Д., Где функция может принимать переменное число аргументов, потенциально разных типов. и обычно использует ключи (или соглашения) из первых аргументов для правильного декодирования оставшихся аргументов.

Обратный вызов - это другой пример, где в коде иногда требуется указывать функцию, которая будет вызываться при событии. Многие фреймворки требуют, чтобы обратный вызов совпадал с предопределенным «typedef», где код позже приведёт аргументы к фактическому типу. Например, прототипу «qsort» требуется функция «сравнения», которая в общем случае определяется как «void *», где фактическая функция преобразует параметры в фактический тип.

void qsort(void *base, size_t nmemb, size_t size,
                  int (*compar)(const void *, const void *));

В историческомОбратите внимание, что первоначальные версии «C» (иногда называемые «K & R C») позволяли определять функции без формального списка параметров. Практический опыт доказал, что это рискованно, непродуктивно. В те дни вы могли написать функцию в заголовочных файлах как:

/* in file.h */
int foo() ;
/* in file.c */
int foo(a)
   int a ;
{
}
/* in prog.c */
{
    a(5,4,"x") ;
}
1 голос
/ 01 октября 2019

Нет, потому что вы не можете разыменовать пустой указатель: вы должны знать, какой тип хранится, что делает идею бесполезной.

Возможно, вы ищете вариант типа .

enum type {
    CHAR, INT, DOUBLE, STR
};

typedef struct {
    union {
        char   c;
        int    i;
        double d;
        char   *str;
    };
    enum type t;
} variant;

void displayGenericObjec(variant v)
{
    switch (v.t) {
        case CHAR:
            putchar(v.c);
            break;
        case INT:
            printf("%d", v.i);
            break;
        case DOUBLE:
            printf("%f", v.d);
            break;
        case STR:
            printf("%s", v.str);
            break;
    }
}

variant x;
x.t = INT;
x.i = 42;
displayGenericObject(x);

Это не очень практичное решение, но оно работает для тривиального кода, которому нужно всего несколько типов.

...