проблема в #defining cout?

#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*, ...)’ andconst 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:

Вы объявили main как возвращающий int , но не включили return инструкцию. Вы должны добавить return 0; в конец main функции. В C вам не обязательно return указывать значение из main , но это хороший стиль.

О, и не #define cout printf , это действительно сбивает с толку. Возможно, технически это не незаконно, но тем, кто придет позже, не стоит пытаться поддерживать ваш код.

Комментарии:

1. Если вы ничего не возвращаете из main , компилятор неявно вернет 0. Это не ошибка.