Может это и банально, но я ничего понять не могу. Для ввода начальных значений типа N использую функцию NextInt вида
int NextInt()
{
int x;
scanf("%d",&x);
return x;
}
Да, пусть глупо, или еще как-то, но мне вот просто нравится грешить штучками типа
int N = NextInt(); vector<int> a; a.push_back(NextInt());
Ну так вот, загадка. На вводе четыре числа 1 2 3 4. Я пишу
cout << NextInt() << " " NextInt() << " " << NextInt() << " " NextInt() << endl;
И мне выводится 4 3 2 1 ???? Думаю что же это такое, пишу
printf("%d %d %d %d\n",NextInt(),NextInt(),NextInt(),NextInt());
и опять то же самое 4 3 2 1. Да блин. Промелькнула мысль о скором конце света, но потом все же решил что я вообще ничего не знаю, и функции вычисляются в каком-то неведомом порядке. Ну, думаю, проверим.
int sum(int a, int b)
{
return a + b;
}
cout << sum(1,2) << " " << sum(3,4) << endl;
printf("%d %d\n",sum(5,6),sum(7,8));
И что? Да нет, все по старому.
3 7
11 15
MS VS 2012, спасайте)
Стандарт языка C++ не гарантирует ничего насчет того, что аргументы функций будут вычисляться в каком-то определенном порядке, если я не ошибаюсь.
Но некоторый порядок все же прослеживается, не так ли? Значит либо на больших количествах вызовов начнется разброс, либо тут все же что-то более простое, но непонятное.
Зависит от компилятора, его опций, поведения оптимизатора и фазы луны. Т.е. оптимизатор может при одних опциях вычислять в одном порядке, а при других опциях — в другом. Не стоит так делать. Даже если несколько раз сработает, не факт, что на другой системе (да хотя бы на CF) тоже будет работать.
хотелось бы увидеть на реальном примере(компилятора, или его опций) что это действительно так.
Для начала, это прямо указано в стандарте. К олимпиадам обычно не относится, но если будете использовать такой код в production и при обновлении компилятора/портировании на новую платформу упадёт работающий кусок кода, будет очень нехорошо.
Легко гуглится обсуждение на StackOverflow с примерами (где-то в середине страницы). В другом обсуждении указывается, что уже достаточно давно почти все компиляторы вычисляют справа налево по историческим причинами. Но никто не запрещает такой умной вещи, как оптимизатор, это поменять по каким-то внутренним мотивам.
Спасибо за ответ. Пора бы мне уже привыкать что языки — лишь технология (со своими оговорками), а не догма.
Как другой пример: например, на платформе PowerPC, на которой, в частности, работает мой старый Mac Mini (вполне себе компьютер), используется big-endian порядок байт, в связи с чем возникают спецэффекты при сборке, например, драйверов, который делают что-то из соображений "младший байт — меньший номер", что в общем случае неверно. Раздражает и не позволяет пользоваться таким софтом.
А что должен был показать последний пример с суммами? Там все как и надо выводится по порядку. Было бы странно, если бы перемешался первый и второй аргументы. Вот в каком порядке вызываются функции, если они не влияют друг на друга — загадка.
В первом примере все понятно. Перегруженный оператор вывода выглядит так:
Поэтому происходит следующее: сначала вызывается оператор вывода для operator<< (cout, nextInt()) который возвращает ostream& (в данном случае cout). Теперь вызывается operator<< (operator<< (cout, nextInt()), nextInt()) и т.д. Поэтому все идет с конца.
Со вторым примером видимо стандарт С++ ничего не гарантирует.
А третий пример вообще не понятно для чего там вроде все так как должно быть, а по другому просто никак.
Для краткости обозначим
operator <<
буквойf
. АnextInt()
буквойx
Получается, мы считаем
f(f(f(f(cout, x), x), x), x)
Вспоминаем народную мудрость "никто не гарантирует порядок вычисления аргументов функции". Получаем, что в теории возможен произвольный порядок (зависит от компилятора и оптимизатора). Разве нет?
Да похоже, что тут тоже не определено. Challenge succeeded :-)
Воспользуйтесь дебагером вот в этом коде:
Ну хотя в вашем случае тоже можно воспользоваться дебагером и заметить, что просто всё выполняется в обратном порядке (но как заметили выше на это не стоит полагаться — лучше считать что в рандомном), а потом выводится в соответствии с установленным порядком вывода.