Как массивы "реализованы" в C? - PullRequest
0 голосов
/ 21 мая 2018

Массив - это, в частности, , а не a указатель .Безусловно, оба значения lvalues ​​ содержат (1-мерную) координату некоторой позиции в (1-мерной) виртуальной памяти.Но рассмотрим этот пример.

#include <stdlib.h>
#include <stdio.h>
int main(){
  char buffer0[4096];
  char* buffer1 = malloc(4096);
  printf("lvalue %16p  sizeof %lu\n", (void *) buffer0, sizeof(buffer0));
  printf("lvalue %16p  sizeof %lu\n", (void *) buffer1, sizeof(buffer1));
// Example output:  lvalue   0x7ffcb70e8620  sizeof 4096
// Example output:  lvalue         0x7a4420  sizeof 8
}

Практические различия, которые приходят на ум, таковы:

  1. Массивы знают, насколько они велики (в байтах) (и,по расширению они знают, сколько элементов у них есть);указатели не (но malloc() должны знать, насколько велик указатель, чтобы знать, сколько нужно free(), учитывая только указатель ...!)
  2. Массивы являются "мусором"собрал »(не надо free() их);указатели должны быть освобождены вручную (если они владеют нетривиальным объемом памяти, т. е. через malloc())
  3. Массивы "живут" в стеке (высокие адреса виртуальной памяти, по крайней мере на моей платформе);указатели «живут» в куче (низкие адреса виртуальной памяти)
  4. Массивы распадаются на указатели при передаче в функции
  5. Размеры массивов не могут быть изменены;указатели могут

В целом массивы кажутся намного умнее (но менее универсальными), чем указатели (они знают, насколько они велики, сколько у них элементов и имеют автоматическое управление памятью).


Вопросы

  1. Как массивы "узнают", насколько они велики?Как это реализовано?
  2. В целом, как массивы реализованы на языке Си?(Компилятор делает это, или ядро?

Ответы [ 3 ]

0 голосов
/ 21 мая 2018
  1. Тип массива содержит его размер (в виде константы времени компиляции) и тип его члена.Так как компилятор знает тип всех переменных, он может просто вычислить sizeof(the_array) как sizeof(array_type.element_type) * array_type.element_count.

  2. С точки зрения распределения памяти и т. Д. Они просто обрабатываются как любая другая переменная:

    Если вы объявляете автоматическую переменную типа массива, это добавляет sizeof(the_array_type) байт к размеру кадра стека.Поэтому при вводе функции указатель стека увеличивается на столько, чтобы сохранить содержимое массива, а при выходе из функции он уменьшается на ту же величину.

    Если вы объявляете переменную со статическим значениемдлительность, sizeof(the_array_type) будет зарезервировано в сегменте данных двоичного файла.

    Опять-таки, аналогичным образом обрабатываются все переменные любого типа.Важно лишь то, что массив содержит свои элементы, поэтому его размер равен размеру его содержимого, тогда как указатель просто указывает на его элементы, а его размер полностью не зависит от того, на что он указывает.

    При использованиикак r-выражение вне sizeof, имя массива просто компилируется по его адресу (и вводится как указатель).

    Компилятор делает это или ядро?

    Все это делается компилятором.

0 голосов
/ 21 мая 2018

Как массивы "знают", насколько они велики?Как это реализовано?

Массивы не не знают, насколько они велики - с массивом нет метаданных, указывающих размер (или тип, или что-либо еще). Во время перевода компилятор знает, насколько велик массив, и все, что зависит от этих знаний (арифметика указателей, sizeof операции и т. Д.), Обрабатывается в это время.После того, как машинный код сгенерирован, массивы - это просто тупые куски памяти - невозможно определить во время выполнения , насколько велик массив, глядя на сам объект массива (за исключением изменяемых типов, таких как переменныемассивы длины, sizeof операции вычисляются во время перевода, а не во время выполнения).

В целом, как массивы реализованы на языке Си?(Компилятор делает это, или ядро?

Массивы - не более чем непрерывная последовательность объектов одного типа. Для объявления

T arr[N]; // for any type T

вы получаете

     +---+
arr: |   | arr[0]
     +---+
     |   | arr[1]
     +---+
     |   | arr[2]
     +---+
      ...
     +---+ 
     |   | arr[N-1]
     +---+

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

Индексоперация arr[i] определена как *(arr + i) - учитывая начальный адрес массива, смещение i элементов ( не байтов! ) от этого адреса и разыменование результата.

Вы правы, что массивы не являются указателями - однако, если это не операнд операторов sizeof или унарных &, или строковый литерал, используемый для инициализации массива символов в объявлении, выражение типа массива будет преобразовано («распад») в выражение типа указателя, а значением выражения будет адрес первого элемента массива (опять же, tвсе это делается во время перевода, а не во время выполнения).

Таким образом, когда вы пишете что-то вроде x = arr[i];, компилятор преобразует выражение arr в значение указателя, поэтому операция с индексом работает.

Напротив, когда вы пишете ap = &arr;, компилятор не конвертирует arr в тип указателя.Результат по-прежнему совпадает с адресом первого элемента, но тип отличается - вместо T * тип T (*)[N] или «указатель на массив N-элементов T».

0 голосов
/ 21 мая 2018

Как массивы "узнают", насколько они велики?Как это реализовано?

Компилятор знает это.

В целом, как массивы реализованы на языке Си?(Компилятор делает это или ядро?

Компилятор.

=========================================================================

Здесь необходимо сосредоточиться на том, что массив - это тип . Это производный тип.

Цитирование C11, глава§6.2.5 / P20,

Тип массива описывает непрерывно распределенный непустой набор объектов с конкретным типом объекта-члена, называемым типом элемента. Тип элемента должен быть завершен всякий раз, когда тип массиваТипы массивов характеризуются типом элементов и количеством элементов в массиве. [...]

Так что, по сути, так же, как компилятор знает о размере любого другого типа, он также знает размер типа массива.

Общий размер рассчитывается на основе размера типа элемента, умноженного на количество элементов в этом массиве.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...