c компилятор: массивы как параметры функции - PullRequest
1 голос
/ 06 февраля 2012

Я пишу компилятор для языка "c-like". В настоящее время компилятор поддерживает массивы в локальной области видимости. Доступ к каждому элементу массива можно получить с помощью скобочной записи --- a[0], a[1],.... для поддержки этой структуры данных используется таблица символов для отслеживания символов в текущей области и адреса следующего доступного пространства памяти. Для демонстрации рассмотрим следующий код:

int a[5]; int b;

с использованием реализации стека и с 4-байтовой выровненной памятью: для доступа, например, элемент a[1], я вычисляю ячейку памяти по

element = ((index+1) * 4) + a.Address; // a.Address is the address of a, which is stored in the symbol table, and index is 1 in this case.

Таким образом, таблица символов не хранит адрес каждого отдельного элемента 'a', только адрес символа и, для каждого символа, следующий адрес памяти.

Я предполагаю, что язык c использует реализацию на основе стека для массивов в локальной области, например, что я сделал. Однако как язык C передает локальный массив в качестве параметра функции, как показано ниже?

foo(int[] a) {}

Будет ли компилятор C использовать кучу или стек для прохождения вышеупомянутого массива?

Ответы [ 5 ]

1 голос
/ 06 февраля 2012

C передает массив функции не по ее содержимому, а по адресу.

Следовательно, аргумент функции на самом деле является простым int * и значением, которое вам необходимо отправить.это a.Address.


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

Обратите внимание, что это приносит еще одно осложнение:

Давайте рассмотрим эту функцию:

int f(int arg1, struct some_struct arg2, float arg3);

и давайте вызовем некоторый указатель внутри этой функции как указатель на фрейм стека этой функции.Давайте назовем это bp (базовый указатель).

Итак, в функции вы знаете, что arg1 находится по адресу bp+8 (например), arg2 находится по адресу bp+12 и arg3 находится по адресу bp+36 (при условии sizeof(struct some_struct) равно 20)

Теперь, если вы отправляете массивы по их содержимому, как насчет этой функции?

int f(int arg1, int arg2[], float arg3);

arg1 и arg2 находятся в том же месте, но как насчет arg3?Как вы узнали бы местонахождение arg3?Для этого вам нужно знать размер arg2.

Однако есть решение для этого.Вы можете сохранить размер массива в его первых 4 байтах (или 8 байтах, если вы считаете, что массив может быть больше 4 ГБ).Затем вы можете безопасно передавать массивы по их содержимому (включая их размер).В таком случае адрес a[i] будет a.Address+4(or 8)+i*sizeof(*a).

. Необходимо учитывать несколько компромиссов:

  • Дополнительная память для сохранения размерамассив.Раньше это было проблемой во время рождения C, но теперь, возможно, это больше не проблема.
  • Гораздо медленнее время вызовов функций, потому что нужно копировать массивы.
  • Более надежный кодпотому что связанная проверка может быть сделана во время выполнения.Мне лично это не нравится, хотя вы выполняете медленнее, и ваша программа все равно не должна выходить за границы массива!Это может быть очень полезной опцией для режима отладки.
  • Лучшая sizeof операция для массивов, которая фактически дает размер массива.Это может быть полезно для функций, которые просто получают массив без его размера.Например, strlen будет O (1).
  • Указатели на середину массива будут бесполезны.Подумайте, сортировка слиянием.
  • и т. Д.
0 голосов
/ 06 февраля 2012

Параметры в C всегда находятся в программном стеке Таким образом, даже если переменная будет кучей и вы передадите ей только адрес указателя, параметр все равно будет в стеке. Чтобы быть в куче, вам нужно выделить память (malloc).

Кстати Лучшая книга о Си - «Язык программирования Си» от создателя Си Денниса Ритчи, который, к сожалению, умер несколько месяцев назад. Вы можете посмотреть здесь: http://cg.inf.unideb.hu/eng/rtornai/Kernighan_Ritchie_Language_C.pdf (я не знаю, является ли это юридической ссылкой, просто погуглил ее). Если вы заинтересованы в C, я бы купил эту книгу, она того стоит.

0 голосов
/ 06 февраля 2012

(Следующее относится к C; если вы хотите изменить его на свой язык, тогда непременно продолжайте.)

Во-первых, поймите, что вы не можете передавать массивы в функции. Вы можете только передавать указатели на функции, поэтому, когда вы видите

void f(int a[]) { ... }

Это на самом деле точно так же, как

void f(int* a) { ... }

Теперь, когда я сказал это, я могу сказать, что указатель передается в стеке.

0 голосов
/ 06 февраля 2012

В C массивы распадаются на указатели при передаче в качестве аргументов функции; foo(int a[]) идентичен foo(int * a), и только указатель на первый элемент «выживает» в вызове функции. Невозможно восстановить размер массива из указателя в вызове функции.

0 голосов
/ 06 февраля 2012

int []a не является допустимым параметром, вы наверняка имели в виду int a[].

В C вы не можете передавать массивы в функции и эту форму:

void foo(int a[]) { ... } 

эквивалентно этому:

void foo(int *a) { ... }

C всегда передается по значению, и обычно в стеке хранится копия указателя a.

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