#include <iostream>
#define true false
#define false true
int main() {
std::cout << false << true;
}
Почему он выводит «01»?Каков ожидаемый результат при переопределении true для false и наоборот?
#include <iostream>
#define true false
#define false true
int main() {
std::cout << false << true;
}
Почему он выводит «01»?Каков ожидаемый результат при переопределении true для false и наоборот?
Как отмечает Джерри Коффин, вы не можете определить макрос с именем, которое является ключевым словом.
Однако мы могли бы рассмотреть другой аналогичный пример с четко определенным поведением и тем же результатом. Рассмотрим:
int TRUE = 1;
int FALSE = 0;
#define TRUE FALSE
#define FALSE TRUE
std::cout << FALSE << TRUE;
При использовании FALSE
, он определяется как макро FALSE
и заменяется списком замены этого макроса, который является единственным лексема, TRUE
. Эта замена затем rescanned для последующих макросов для замены.
TRUE
на замену затем идентифицируется как макрос и заменяется его списком замены, который является единственным токеном FALSE
. Эта замена снова повторно сканируется.
Если мы продолжим повторное сканирование и замену, мы закончим бесконечный цикл, поэтому спецификации предварительной обработки C (и C++) утверждают, что замена макроса никогда не повторяется в списке заметок.
С заменой FALSE
в этом окончательном списке замены приведет к рекурсии, макро замена прекращается, и мы остались с FALSE
, что имя из int
со значением 0
.
Хорошее объяснение! Но только один вопрос, вы даете ему идеи написать больше кода, как указано выше ???? – noMAD
Он этого не писал. –
@noMAD: Нет, обычно не следует писать такой код, но это не значит, что мы не должны объяснять, почему этот код работает так, как он делает. Важно понимать, как работает ваш язык программирования, даже в «глупых» углах языка, который «никто не использует». Для записи я написал код именно так, в модульном тесте для реализации препроцессора C, над которым я работал некоторое время (по общему признанию, у меня странные увлечения). –
Любая попытка переопределения зарезервированного слова дает неопределенное поведение.
Edit:
§2.11/1: "Идентификаторы, приведенные в таблице 3, зарезервированы для использования в качестве ключевых слов" Я не буду пытаться воспроизвести всю таблицу 3, но она включает как ложные, так и истинные. Может быть открытым вопрос о том, является ли это абсолютным запретом, хотя, поскольку такое же предложение добавляет: «(то есть они безоговорочно рассматриваются как ключевые слова на этапе 7)», что предполагает, что можно переопределить ключевые слова так как задействованные макросы будут/расширены до фазы 7.
В этом случае, однако, вы также включили <iostream>
, что вводит другое правило (§17.4.3.1.1): «Перевод единица, которая включает заголовок, не должна содержать макросов, которые определяют имена, объявленные или определенные в этом заголовке. Кроме того, такая единица перевода не определяет макросы для имен, лексически идентичных ключевым словам ».
Формулировка здесь настоятельно указывает на то, что существует намерение, что если единица перевода не содержит заголовок, было бы свободно переопределять ключевое слово, как вы это делали, но с учетом наличия #include <iostream>
не сомневайтесь, что у вас есть неопределенное поведение.
Как только у вас есть неопределенное поведение, на самом деле больше нечего сказать о «почему», что-то происходит - в этот момент в стандарте очень ясно, что любое поведение допустимо.
Серьезно? Вы написали этот код? Определить 'true' на' false' и наоборот? Найдите ближайший ботинок и побейте себя над головой, пока не выясните, в чем проблема. –
Я не написал этот код (= Я просто хочу понять – hired777
Возможно, это объясняется малоизвестным, обычно неясным (но очень актуальным в некоторых случаях) фактом, касающимся расширения макросов, но когда вы начинаете цитирование стандарта, вы можете также коротко закоротить и указать, что сказал Джерри Коффин. Что касается ИСО, то компилятор может начать революцию роботов и заставить роботов бить автора с ближайшим ботинком, чтобы сделать @CodyGray счастливым. – delnan