#c
#c
Вопрос:
Мой друг сказал мне, что в этом коде есть некоторые проблемы:
#include <iostream>
#include <cstdio>
using namespace std;
#define cout printf
int main(){
cout("cout");
}
Он не назвал мне причину и попросил разобраться, чего я не смог. Код, кажется, работает нормально, что в нем может быть не так?
Комментарии:
1. Это неправильно, потому что вы переопределяете
cout
, чтобы быть псевдонимомprintf
. И это совершенно разные животные.2. Технически это не так. Это неправильно с моральной точки зрения. Я думаю, это то, что имел в виду ваш друг.
3. Это почти наверняка также станет неправильным технически, и, скорее всего, скорее раньше, чем позже.
4. «Кажется, работает» — это как «Я перешел улицу, не глядя, не был сбит автобусом». Хочешь попробовать еще раз?
5. Переопределение существующих имен с помощью препроцессора всегда неверно.
Ответ №1:
Насколько я знаю, Стандарт запрещает определять имена (с #define), объявленные в заголовке любой стандартной библиотеки.
Нашел это в n3290 ($ 17.6.4.3.1)
17.6.4.3.1 Имена макросов [macro.names]
1 Модуль перевода, который включает заголовок стандартной библиотеки, не должен иметь имен #define или #undef, объявленных ни в одном заголовке стандартной библиотеки.
Комментарии:
1. Я почти уверен, что это правда, но я буду удивлен, если смогу найти доказательства. Я знаю, что это применимо, по крайней мере, к ключевым словам, но
cout
вряд ли это ключевое слово.2. Имена не являются ключевыми словами, а ключевые слова никогда не могут быть объявлены или определены. Как таковое это, безусловно, относится к
cout
.3. Другими словами, если бы он удалил
#include <iostream>
строку, его программа была бы легальной, просто сбивающей с толку. На данный момент это даже не нужно компилировать.4. Законно писать бесконечный рекурсивный цикл, который блокирует ваше приложение.
5. @Prasoon, @Dennis: Я не знаю, где вы это точно нашли, но в моей копии n3290 написано «Модуль перевода, который включает заголовок стандартной библиотеки, не должен иметь имен #define или #undef, объявленных ни в одном заголовке стандартной библиотеки.», поэтому удаление
<iostream>
не делает его допустимой программой, поскольку он по-прежнему включает cstdio.
Ответ №2:
Хотя вы можете утверждать, что этот код «кажется, работает нормально», подумайте о нескольких годах спустя, когда ваш исходный файл из 7 строк станет исходным файлом из 7 сотен строк, и вы не единственный сопровождающий.
Вы перешли от написания printf
инструкций в стиле C в исходных файлах C и добавляете (или другой сопровождающий добавляет) следующую строку совершенно корректного C :
cout << "What is wrong with my perfectly valid C code? " << endl;
И ваш компилятор сообщает:
test.cpp:699: error: invalid operands of types ‘int ()(const char*, ...)’ and ‘const char [29]’ to binary ‘operator<<’
Целый мир боли!
Ответ №3:
ДА. У него есть проблема.
Начиная с C , можно обычно писать cout << 1000
, что в данном случае было бы ошибкой, но в остальном это вполне нормально в C .
Что дальше? Вы пытаетесь определить это:
#define scanf cin
//so that you can use it as
scanf >> variable; //not so kewl.
Мой совет таков :
Не пытайтесь изменить значение таких имен. В конце концов, что вы получите, сделав это? Ничего.
Ответ №4:
У него проблемы с обслуживанием, потому что вы переопределили хорошо известные функции для работы по-другому. Таким образом, ни один другой программист не захочет работать над этим кодом.
Похожие:
#define MULTIPLY(a, b) (a b)
#define FIVE 12
#define THREE 3
int main(void)
{
return MULTIPLY(FIVE, THREE);
}
Это дает правильный ответ, но совершенно не поддерживается.
Ответ №5:
Вы объявили В C вам не обязательно main
как возвращающий int
, но не включили return
инструкцию. Вы должны добавить return 0;
в конец main
функции. return
указывать значение из main
, но это хороший стиль.
О, и не #define cout printf
, это действительно сбивает с толку. Возможно, технически это не незаконно, но тем, кто придет позже, не стоит пытаться поддерживать ваш код.
Комментарии:
1. Если вы ничего не возвращаете из main , компилятор неявно вернет 0. Это не ошибка.