При добавлении элемента * void в массив * void, как компилятор узнает, сколько байтов нужно использовать в памяти? - PullRequest
2 голосов
/ 26 марта 2020

Недавно я начал немного больше узнавать о структурах данных, а затем, при реализации концепции очереди в C, я столкнулся со следующим:

typedef struct {
  int max;        /* Max. enqueed items. */
  int total;      /* Total enqueued. */
  int pos_start;  /* Pos. of first item. */
  int pos_end;    /* Pos. of last item. */
  int item_size;  /* Byte size of each item. */
  void** items;   /* Array of items. */
} queue_t;

/* 
 * Omitted code for brevity purposes. 
 */

void
queue_add(queue_t* queue, void* item)
{
  if (queue_full(queue))
  {
    fprintf(stderr, "Tried to add an item into a full queue");
    exit(1);
  }

  queue->items[queue->pos_end] = item;
  queue->total++;
  queue->pos_end = find_next_end(queue);
}

Видимо, это работает. Пара замечаний:

  1. В оригинальном руководстве рассказывалось, как создать очередь из целых чисел. Я пытался бросить вызов самому себе, создав очередь «любого» элемента - вот почему я пытаюсь использовать массив из void* элементов.
  2. Из-за того, что я использую массив void* элементы, я знаю, что всякий раз, когда я хочу использовать какой-либо элемент из этой очереди (например, в основной функции с помощью queue_pop), мне нужно выполнить правильное приведение. Используя приведение, компилятор может точно знать, сколько байтов эта переменная должна занять в памяти.

Однако, мой большой вопрос :

На основании моего функция, когда я помещаю sh новый элемент в очередь, я сохраняю его в queue->items[queue->pos_end]. Если компилятор не знает, сколько байтов item имеет (как он помечен как void*), как он вычисляет адрес памяти для queue->items[queue->pos_end]?

Ответы [ 2 ]

2 голосов
/ 26 марта 2020

Указатели всегда являются полными типами, включая (возможно, cv-квалифицированный) тип указателя void * или void **.

Из стандарта C (6.2.5 Типы, стр. # 20)

- тип указателя может быть получен из типа функции или типа объекта, называемого ссылочным типом. Тип указателя описывает объект, значение которого предоставляет ссылку на объект ссылочного типа. Тип указателя, полученный из ссылочного типа T, иногда называют «указателем на T». Конструкция типа указателя из ссылочного типа называется «выводом типа указателя». Тип указателя является полным типом объекта.

Вот демонстрационная программа.

#include <stdio.h>

int main(void) 
{
    printf( "sizeof( void * ) = %zu\n", sizeof( void * ) );

    return 0;
}

Выходные данные могут быть

sizeof( void * ) = 8

Так что если у вас есть массив с типом элемента void *, то компилятор использует значение 8 в арифметике указателя c относительно доступа к элементам массива.

2 голосов
/ 26 марта 2020

компилятор не знает, сколько байтов имеет элемент (поскольку он помечен как void*)

Компилятор точно знает, из каких байтов состоит item, потому что его тип - указатель (на void или на int, или на другой указатель, или на что-либо еще - не имеет значения), и все указатели имеют одинаковый размер (обычно 4 или 8 байт).

...