Как поддерживались разные подписи C для main до _Generic? - PullRequest
0 голосов
/ 23 апреля 2019

_Generic стал доступен с C11, а до этого в C99 tgmath.h включал аналогичную функциональность с использованием специальных хаков для компилятора.

но как у main было несколько подписей в K & R C или C89 / C90?

есть как минимум 2 сигнатуры функций для main (), о которых я знаю:

1: int main(int argc, const char *argv[]);

2: int main(void);

Ответы [ 3 ]

3 голосов
/ 23 апреля 2019

Стандарт C требует, чтобы реализация поддерживала только две подписи, указанные в вопросе,

1: int main(int argc, const char *argv[]);

2: int main(void);

Для соглашений о вызовах, когда вызывающий объект извлекает аргументы из стека вызовов, последовательность вызова для (1)прекрасно работает для (2) - вызывающая сторона помещает аргументы в стек, вызываемая сторона (main) никогда не использует их, а вызывающая сторона удаляет их из стека.

Для соглашений о вызовах, когда вызываемый объект появляетсяаргументы из вызывающего стека main должны были бы быть скомпилированы по-разному в зависимости от того, какая подпись используется.Это было бы проблемой в реализациях с фиксированным фрагментом кода запуска во время выполнения C, поскольку он не знает, как было объявлено main.Самый простой способ справиться с этим - всегда использовать соглашение о вызовах «вызывающих вызовов» для main, и именно так работает компилятор Microsoft C - см., Например, https://docs.microsoft.com/en-us/cpp/build/reference/gd-gr-gv-gz-calling-convention,, в котором говорится, что другие вызовыусловные обозначения игнорируются, когда применяются к main.

PS

  • _Generic и tgmath.h не оказали никакого влияния на это.

  • В K & R C не было подписей, только имена аргументов и необязательные объявления типов для них, поэтому для main.

было только одно возможное соглашение о вызовах.Таким образом, ни одно из этих языковых изменений за десятилетия никак не повлияло на то, как называется main.

3 голосов
/ 23 апреля 2019

но как у main было несколько подписей в K & R C или C89 / C90?

main не имели несколько подписей per se в K & R C. Эта версия не имела смысла "подписи", как вы это понимаете. Хотя у функций действительно были ожидания относительно количества и типов их аргументов, и их поведение определялось только в том случае, если эти ожидания были удовлетворены, аргументы функции не составляли часть объявлений функций.

Следующая цитата из раздела 5.11 первого издания Язык программирования C (Kernighan & Ritchie, 1978) может светиться:

Когда main вызывается для начала выполнения, он вызывается с двумя аргументами.

Это безусловное утверждение: main вызывается (всегда) с двумя аргументами в C, как описано в K & R. Компиляторы могут делать все, что им нужно или нужно, в случаях, когда эти параметры не были объявлены.

Случай не особо отличается в C90 или любой более поздней версии C (все из которых все еще поддерживают определения функций в стиле K & R). Даже когда main объявлено с прототипом, реализации делают все, что хотят или должны делать. Например, возможно, они генерируют код для стандартной подписи и выполняют любое необходимое исправление рекурсивных вызовов для main() во время компоновки. Или, может быть, они генерируют код для любого (поддерживаемого) объявления main() и обрабатывают его в какой-то специфической для ОС оболочке. Может быть, в некоторых реализациях ничего особенного не требуется.

0 голосов
/ 23 апреля 2019

C имел и не имеет сигнатуры функции.Конечно, ничего конкретного параметра.Большинство компиляторов добавляли (а некоторые добавляли) подчеркивание ("_") для создания пространства имен компоновщика бедного человека, что позволяло легко предотвращать конфликты имен символов.

Таким образом, запуск среды выполнения C всегда будет иметь один однозначный символдля запуска.Чаще всего _main.

start:
 ;#  set up registers
 ;#  set up runtime environment:
 ;#  set up stack, initialize heap, connect stdin, stdout, stderr, etc.
 ;#  obtain environment and format for use with "envp"
 ;#  obtain command line arguments and set up for access with "argv"
 push  envp
 push  argv
 push  argc    ; number of arguments in argv
 call  _main

 push  r0
 call  exit

.end  start
...