Несколько функций main

99
26 октября 2021, 04:40

Легален ли следующий код с точки зрения стандарта?

#include <iostream>

int main() {
    std::cout << "main\n";
}
#define main not_main
int main() {
    std::cout << "not main\n";
    return 0;
}

Все комментаторы говорят, что да, но почему тогда тут написано

It cannot be predefined and cannot be overloaded: effectively, the name main in the global namespace is reserved for functions

?

Answer 1

Вы путаете уровень процессора (компилятора) и препроцессора (предкомпилятора). Данные понятия нельзя смешивать, иначе это приводит к "логической нестыковке". Вначале код проходит стадию препроцессора, где расшифровуются все принятые макросы - я их назову сокращения. И уже расшифрованый код компилируется, т.е. код легален, в коде обьявлено две функции c разными именами. Одна обьявлена main, а другая not_main с помошью макроса ("сокращения") main. Создайте map-файл - и увидите что функции две. На время прохождения препроцессором участка от #define до #undefine макрос будет иметь силу, но это не означает что компилятор получит два одинаковых названия. У компилятора линкера и других инструментов будет два разных имени.

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

Рассмотрим на кошечках. Давайте договоримся что собака означает кошка. А потом вы говорите что "все собаки кошки" (которые до уговора) - это неверное суждение. "Откройте толковый словарь, там неправильно написано про собак" - тоже неверное суждение. Кошка равно собака - лишь на время действия уговора, но даже при этом она по-сути не становится собакой. Просто мы на время решили так условиться. Кто не видит что "условились" может сразу не понять в чём дело. Вот примерно так работают макросы на данном примере.

В справке не написано потому что... Поскольку препроцессор работает отдельно от компилятора, то считается что 1) его работу вы или знаете и понимаете, поскольку если на каждой странице напоминать что существует препроцессор, и очень важно понимать как он работает - это будет достаточно громоздко 2) что тот кто не знает препроцессор не использует его. Поэтому часто использование #define считается плохим тоном. Точнее плохой тон - использовать его просто-так там где это не нужно. Использование макросов может сбивать с толку анализаторы подстветку синтаксиза, и людей читающих ваш код.

Цель препроцессора - несколько иная. Сделать код более читабельным, объеденять большие куски кода вместе, можно делать свёртки кода, можно следитить за версионностью, используя макросы достигают кросс-платформенности, деление на дебаг-релиз и возможно некоторые другие нестандартные вещи. Софт не запрещает использовать препроцессор для запутывания кода, то что сделали вы.

Фраза the name main in the global namespace is reserved for functions - означает что main глобального пространства имен зарезервирована как точка входа в программу, и если вы её обьявите в другом пространстве имен (namespace) - то она не будет выполнять ф-цию точки входа. Просто даное предложение невозможно "дословно" слово-в-слово перевести.

Учасник VTT верно заметил, что "predefined" не подразумевает pre + "#defined". Думаю что текст выше обьясняет почему.

Полезные ссылки: http://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%D0%BE%D1%80_%D0%A1%D0%B8

READ ALSO
C++ - volatile при замере времени

C++ - volatile при замере времени

Есть вот такой вот код, замеряющий время работы трех разных функции умножения матриц и записывающий их в файл:

98
Передача string_view по ссылке или значению

Передача string_view по ссылке или значению

Как правильно передавать std::string_view в функцию, если не надо изменять строку?

179
Как компилировать быстрее?

Как компилировать быстрее?

Есть Incredibuild, но она вроде платная?

83