Легален ли следующий код с точки зрения стандарта?
#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
?
Вы путаете уровень процессора (компилятора) и препроцессора (предкомпилятора). Данные понятия нельзя смешивать, иначе это приводит к "логической нестыковке". Вначале код проходит стадию препроцессора, где расшифровуются все принятые макросы - я их назову сокращения. И уже расшифрованый код компилируется, т.е. код легален, в коде обьявлено две функции 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
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть вот такой вот код, замеряющий время работы трех разных функции умножения матриц и записывающий их в файл:
Как правильно передавать std::string_view в функцию, если не надо изменять строку?