Как сохранить любой тип в void * во время выполнения? - PullRequest
0 голосов
/ 20 октября 2018

Я пишу динамический массив в C:

struct array {
  int len;
  int cap;
  void *data;
};

Легко хранить значения, если я знаю тип:

void set(array* a, int idx, int val) {
    ((int*)a->data)[idx] = val;
}

Но я хочу принять любой тип (void *):

void set(array* a, int idx, void* val) {
    a->data[idx] = val;
}

Это, очевидно, не компилируется, потому что 'void' is not assignable

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

Есть ли способ сделать это самостоятельно?Работайте непосредственно с байтами, что-то вроде

void set(array* a, int idx, void* val, int size) {
    *((char*)a->data + size * idx) = val;
}

По сути, я хочу сделать их похожими на фрагменты Go.Вы можете прочитать об их встроенных универсальных типах здесь:

https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics

Нет шаблонов, нет распаковки.Они используют void* для хранения данных.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Полагаю, memcpy должен делать то, что вы ищете:

void set(array* a, int idx, void* val, int size) {
    memcpy(a->data + size * idx, val, size);
}
0 голосов
/ 20 октября 2018

Прежде всего вам нужно использовать void * * data - для хранения массива, а не один указатель на элемент.

из того, что у вас есть [a-> data = (void *) val;] должен работать нормально.

это только указатель на данные, и он может быть сохранен как void.вам нужно знать, как читать данные, когда вы захотите прекратить ссылаться на них.

если val указывает на int, чтобы прочитать его, вам придется привести его, чтобы компилятор знал, сколько байтов нужно прочитать.итак: * (int *) (a-> data);

...