Где находятся параметры основной функции C / C ++? - PullRequest
58 голосов
/ 16 ноября 2010

В C / C ++ основная функция получает параметры типа char*.

int main(int argc, char* argv[]){
  return 0;
}

argv - это массив char* и указывает на строки.Где находятся эти строки?Они в куче, в стеке или где-то еще?

Ответы [ 10 ]

31 голосов
/ 16 ноября 2010

Они магия компилятора и зависят от реализации.

28 голосов
/ 16 ноября 2010

Вот что говорит стандарт C ( n1256 ):

5.1.2.2.1 Запуск программы
...
2 Если ониобъявлены, параметры функции main должны соответствовать следующим ограничениям:

  • Значение argc должно быть неотрицательным.

  • argv [argc] должен быть нулевым указателем.

  • Если значение argc больше нуля, члены массива argv [0] - argv [argc-1] включительно должен содержать указатели на строки, которым перед установкой программы передаются значения, определяемые реализацией средой хоста.Намерение состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другого места в размещенной среде.Если среда хоста не может предоставлять строки с буквами как в верхнем, так и в нижнем регистре, реализация должна обеспечить получение строк в нижнем регистре.

  • Если значение argc больше нуля, строка, на которую указывает argv [0] , представляет имя программы ; argv [0] [0] должен быть нулевым символом, если имя программы недоступно из среды хоста.Если значение argc больше единицы, строки, на которые указывают argv [1] - argv [argc-1] , представляют программу параметры .

  • Параметры argc и argv и строки, на которые указывает массив argv , должны изменяться с помощьюпрограмму, и сохраните свои последние сохраненные значения между запуском программы и завершением программы.

Последний пункт наиболее интересен для хранения значений строк.Он не определяет кучу или стек, но требует, чтобы строки были доступны для записи и имели статический экстент, что накладывает ограничения some на то, где может находиться содержимое строки.Как уже говорили другие, точные детали будут зависеть от реализации.

16 голосов
/ 16 ноября 2010

На самом деле это сочетание зависимости компилятора и зависимости операционной системы.main() - это функция, как и любая другая функция C, поэтому расположение двух параметров argc и argv будет соответствовать стандартному для компилятора на платформе.Например, для большинства компиляторов C, нацеленных на x86, они будут в стеке чуть выше адреса возврата и сохраненного базового указателя (запомните, что стек растет вниз).На x86_64 параметры передаются в регистрах, поэтому argc будет в %edi и argv будет в %rsi.Код в основной функции, сгенерированный компилятором, затем копирует их в стек, и именно на это указывают более поздние ссылки.Это так, что регистры могут использоваться для вызовов функций из main.

Блок char* s, на который указывает argv, и фактические последовательности символов могут быть где угодно.Они начнутся в некотором месте, определенном операционной системой, и могут быть скопированы с помощью кода предварительной посылки, который компоновщик генерирует в стек или где-то еще.Вам нужно будет посмотреть код для exec() и преамбулу ассемблера, сгенерированную компоновщиком, чтобы узнать.

8 голосов
/ 16 ноября 2010

Ответ на этот вопрос зависит от компилятора. Это означает, что это не рассматривается в стандарте C, поэтому любой может реализовать его так, как ему хотелось бы. Это нормально, поскольку и в операционных системах нет общепринятого, стандартного способа запуска процессов и их завершения.

Давайте представим простой, почему бы и нет сценарий.

Процесс каким-то механизмом получает аргументы, записанные в командной строке. Тогда argc - это просто int, который помещается в стек с помощью функции начальной загрузки, которую компилятор устанавливает в качестве точки входа для процесса программы (часть времени выполнения). Фактические значения берутся из операционной системы и могут быть, скажем, записаны в блоке памяти кучи. Затем создается вектор argv, и адрес его первой позиции также помещается в стек.

Затем вызывается функция main (), которую должен предоставить программист, и ее возвращаемое значение сохраняется для последующего (почти промежуточного) использования. Структуры в куче освобождаются, а код выхода, полученный для main, экспортируется в операционную систему. Процесс заканчивается.

3 голосов
/ 16 ноября 2010

Как отмечают многие другие ответы, точный механизм, используемый реализацией компилятора для передачи аргументов в main, не определен стандартом (как и механизм, который компилятор использует для передачи любых аргументов в функцию).Строго говоря, компилятору даже не нужно передавать ничего полезного в этих параметрах, поскольку значения определяются реализацией.Но ни один из них не является особенно полезным ответом.

Типичная программа на C (или C ++) скомпилирована для так называемой «размещенной» среды выполнения (с использованием функции main() в качестве начальной точки вашей программытребований к размещаемой среде).Главное, что нужно знать, это то, что компилятор упорядочивает вещи так, что когда исполняемый файл запускается операционной системой, среда выполнения компилятора первоначально получает управление, а не функцию main().Код инициализации среды выполнения выполняет любую необходимую инициализацию, включая выделение памяти для аргументов main(), затем передает управление main().

Память для аргументов main() может быть получена из кучи, может быть выделен в стеке (возможно, с использованием методов, которые недоступны для стандартного кода C), или может использовать статически распределенную память, хотя это менее вероятный вариант только потому, что он менее гибок.Стандарт требует, чтобы память, используемая для строк, на которые указывает argv, была модифицируемой и чтобы изменения, внесенные в эти строки, сохранялись на протяжении всего жизненного цикла программы.

Просто имейте в виду, что до выполнения main() вполненемного кода уже запущено, что настраивает среду для запуска вашей программы.

3 голосов
/ 16 ноября 2010

Эти параметры ничем не отличаются от параметров любой другой функции. Если вызывающая последовательность архитектуры требует, чтобы параметры проходили через стек, они находятся в стеке. Если, например, x86-64, некоторые параметры записываются в регистры, они также включаются в регистры.

2 голосов
/ 16 ноября 2010

Как упоминается pmg, когда main вызывается рекурсивно, это зависит от вызывающей стороны, на которую указывают аргументы.По сути, ответ тот же на исходный вызов main, за исключением того, что «вызывающий» - это реализация / ОС C.

В системах UNIX-y строки, на которые указывает argv,argv сами указатели, а начальные переменные среды процесса почти всегда хранятся в самом верху стека.

2 голосов
/ 16 ноября 2010

Обычно неизвестно где они.

#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
  char **foo;
  char *bar[] = {"foo", "bar"};

  (void)argv; /* avoid unused argv warning */

  foo = malloc(sizeof *foo);
  foo[0] = malloc(42);
  strcpy(foo[0], "forty two");

  /* where is foo located? stack? heap? somewhere else? */
  if (argc != 42) main(42, foo); else return 0;

  /* where is bar located? stack? heap? somewhere else? */
  if (argc != 43) main(43, bar); else return 0;
  /* except for the fact that bar elements
  ** point to unmodifiable strings
  ** this call to main is perfectably reasonable */

  return 0;
  /* please ignore memory leaks, thank you */
}
2 голосов
/ 16 ноября 2010

Список аргументов является частью среды процесса, аналогичной (но отличной от) переменных среды.

0 голосов
/ 16 ноября 2010

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

...