Mmap, пустой указатель и приведение типов в C - PullRequest
1 голос
/ 28 апреля 2020

Я читаю C на диске ха sh код таблицы, не зная много о C или mmap, но я знаю Golang.

Этот фрагмент кода смущает меня. Есть две структуры, подобные этой.

typedef struct HashTbl
{
    void *data;
    ...
} HashTbl;
typedef struct Header
{
    char magic[16];
    size_t total;
    size_t used;
} Header;

Используется mmap для сопоставления HashTbl data свойство

ht->data = mmap(NULL, data_size, prot, MAP_SHARED, file, 0);

ht тип равен HashTbl, ht->data будет приведен к Header для установки значения свойства следующим образом:

Header *h = (Header *)ht->data;
strcpy(h->magic, MAGIC_STR);
h->total = 12;
h->used = 0;

Тогда эта функция:

void *hashtable_of(HashTbl *ht)
{
    return (unsigned char *)ht->data + sizeof(Header);
}

использование этой функции:

uint64_t *table = (uint64_t *)hashtable_of(ht);

Я не понимаю, какова цель этой функции, заключается в том, чтобы вычислить длину значения void pointer (Header::data)?

void pointer в C выглядит как interface{} в Go, что может быть приведенным к любому типу. но Go имеет обработку ошибок при выполнении приведения типов, если мы приведем тип interface{} к неверному типу, он вернет ошибку

Но в этом коде C он преобразует Struct -> unsigned char pointer и объединить его с sizeof другой структурой, что означает, что unsigned char pointer является целым числом?!

Как это вообще возможно?

1 Ответ

2 голосов
/ 28 апреля 2020

он приводит Struct -> unsigned char pointer и объединяет его с размером другой структуры, что означает, что указатель на символ без знака является целым числом?

void *hashtable_of(HashTbl *ht)
{
    return (unsigned char *)ht->data + sizeof(Header);
}

Не совсем. Код начинается с одного указателя, ht, и определяет другой указатель, указатель возврата.

Не существует приведение struct. Существует приведение unsigned char *.

. В этом коде нет целых чисел, кроме sizeof(Header).


Давайте рассмотрим его по шагам:

Указатель ht содержит элемент .data, на который ссылается ht->data. Это приводит к void *.

void * приводится к указателю unsigned char.

Затем код выполняет добавление указателя с помощью ... + sizeof(Header). Добавление указателя подобно целочисленному сложению , но имеет различия. Здесь добавление указателя и целого числа приводит к еще одному указателю unsigned char, который находится дальше в памяти на sizeof(Header) байт (unsigned char).

Наконец этот указатель unsigned char преобразуется в void * как часть return.


hashtable_of() общее использование неясно без окружающего кода.


void pointer в C выглядит как интерфейс {} в Go, который может быть приведен к любому типу.

Почти. Указатель void может быть приведен к любому указателю объекта с ограничениями допустимости и выравнивания значений. Указатель void может быть недостаточным для представления указателя function . C не хватает портативного универсального указателя.

...