Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.90/29: Рейтинг темы: голосов - 29, средняя оценка - 4.90
1 / 1 / 0
Регистрация: 31.07.2014
Сообщений: 55

Вывод результата несколько раз отработанной функции в одну строку

12.05.2016, 00:31. Показов 6124. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Очень интересный момент нашел я для себя сегодня в С++.
А точнее в выводе средствами iostream
Прошу Вас объяснить, что происходит.
Код простой, объяснять не буду
C++
1
2
3
4
5
6
7
8
9
10
int i = 0; //global variable
int foo(){
    i++;
    return i+2*2;
}
int main()
{
    cout << foo() << foo() << foo() << foo() << endl;
    return 0;
}
Выводит 8 7 6 5, хотя должно наоборот: 5 6 7 8
Если вызывать cout'ы следующим образом, все нормально:
C++
1
2
3
4
cout << foo();
cout << foo();
cout << foo();
cout << foo() << endl;
Выводит 5 6 7 8
Я так понимаю это связано с особенностью обработки функций на уровне ассемблера, и результат возвращающийся из функции
идет в стек, а потом поэлементно оттуда достается?
Прошу объяснить, очень хочется понять как все это правильно происходит. Заранее спасибо!
P.S: Два часа голову ломал, пока не обнаружил, что ошибка в выводе
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.05.2016, 00:31
Ответы с готовыми решениями:

Вывод результата в одну строку
Подскажите кто знает , пишу в скрипте две команды, они выводят результат как положено , а как сделать чтобы вывод был в одну строку ...

Надо вывести переменную несколько раз в одну строку
import random as r b = 0 while b &lt; 10: letter = a = r.choice(letter) size = r.randint(0,1) if size == 0: ...

SLQ запрос выводит несколько раз одну и туже строку
День добрый. Запрос начал выдавать результат копируя строки и выдавая их по несколько раз. В какую сторону копать? В конце добавил...

16
18 / 17 / 22
Регистрация: 03.05.2016
Сообщений: 105
12.05.2016, 00:36
Из-за приоритета, есть в книге Кернигана и Ритчи
для данного оператора справа налево, поэтому так и выводит

Добавлено через 45 секунд
Операторы Выполняются
() [] -> . слева направо
! ~ ++ -- + - * & (тип) sizeof справа налево
* / % слева направо
+ - слева направо
<< >> слева направо
< <= > >= слева направо
== != слева направо
& слева направо
^ слева направо
| слева направо
&& слева направо
|| слева направо
?: справа налево
= += -= *= /= %= &= ^= |= <<= >>= справа налево
, слева направо
0
1 / 1 / 0
Регистрация: 31.07.2014
Сообщений: 55
12.05.2016, 00:40  [ТС]
Извините, Вы сами написали в списке, что для << и >> слева направо
А для >>= или <<= и им подобных это я понимаю, справа налево
А также, если смотреть выражение:
C++
1
cout << "Hi, my dear" << " friends!" << endl;
Оно ведь слева направо выводится.
Подозреваю, что дело все таки в правильном вычислении функций и стэке.
0
18 / 17 / 22
Регистрация: 03.05.2016
Сообщений: 105
12.05.2016, 00:45
ща гляну
0
 Аватар для Armatus
56 / 56 / 44
Регистрация: 24.03.2016
Сообщений: 378
12.05.2016, 00:46
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <algorithm>
using namespace std;
int foo();
 
int i = 0;
int main()
{
    cout << foo();
    cout << foo();
    cout << foo();
    cout << foo();
    cout << foo();
 
    return 0;
}
int foo() {
    i++;
    return i + 2 * 2;
}
Вот так работает правильно, сам не понимаю)
0
12.05.2016, 00:49  [ТС]

Не по теме:

Поэтому тему и создал)
Интересный момент

0
18 / 17 / 22
Регистрация: 03.05.2016
Сообщений: 105
12.05.2016, 00:58
Тоже склоняюсь, что дело в порядке помещения в стек
Последним пришёл - первым ушёл
вычисляется в порядке
5, потом накладывается 6 и т.д. Потом выводятся значения по порядку, поэтому в самом верху стека лежит последнее вычисление. Т.к. если всунуть слово между ф-циями, оно появляется где надо
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
12.05.2016, 01:05
Цитата Сообщение от Hilarior Посмотреть сообщение
Тоже склоняюсь, что дело в порядке помещения в стек
Последним пришёл - первым ушёл
Вот тут почитайте.
1
18 / 17 / 22
Регистрация: 03.05.2016
Сообщений: 105
12.05.2016, 01:14
Mr.X, чего не знал того не знал, признаю)
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12932 / 6800 / 1820
Регистрация: 18.10.2014
Сообщений: 17,211
12.05.2016, 01:44
Лучший ответ Сообщение было отмечено Ilot как решение

Решение

Цитата Сообщение от Alex_The_King Посмотреть сообщение
Я так понимаю это связано с особенностью обработки функций на уровне ассемблера, и результат возвращающийся из функции
идет в стек, а потом поэлементно оттуда достается?
Это ни с чем конкретным не связано, ни с "ассемблером", ни со "стеком". В языке С++ порядок вычисления подвыражений в выражении не специфицирован и может быть любым (за исключением особых операторов, типа логических, ?: или ,, с ясно оговоренной упорядоченностью).

Язык С++ гарантирует, что перегруженные операторы << буду вызываться по порядку, слева направо. Однако в каком порядке будут подготавливаться операнды для этих вызовов (т.е. делаться индивидуальные вызовы foo()) - не оговаривается.

Поэтому никакого формально предсказуемого порядка тут нет.
1
Эксперт по математике/физикеЭксперт С++
 Аватар для Ilot
2223 / 1425 / 420
Регистрация: 16.05.2013
Сообщений: 3,642
Записей в блоге: 6
12.05.2016, 12:23
Рассмотрим код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
int i = 0; //global variable
int foo1(){
    i++;
    std::cout << "I'm foo1 " << i+2*2 << std::endl;
    return i+2*2;
}
int foo2(){
    i++;
    std::cout << "I'm foo2 " << i+2*2 << std::endl;
    return i+2*2;
}
int foo3(){
    i++;
    std::cout << "I'm foo3 " << i+2*2 << std::endl;
    return i+2*2;
}
int main() {
    std::cout./**3*/operator<<(foo3())./**2*/operator<<(foo2())./**1*/operator<<(foo1());
    return 0;
}
Строка:
C++
1
std::cout./**3*/operator<<(foo3())./**2*/operator<<(foo2())./**1*/operator<<(foo1());
Есть тоже самое, что и
C++
1
std::cout << foo() << foo() << foo();
Вывод:
I'm foo1 5
I'm foo2 6
I'm foo3 7
765

Теперь разберемся, что происходит на самом деле.
Сперва вызывается функция operator<< с аргументом возвращаемым функцией foo1. Однако известно, что функции члены принимают неявно первым параметром указатель this. Поэтому второй этап это получение ссылки this которая возвратиться при вызове operator << с параметром возвращаемым foo2 и т.д. Т.е. на первом этапе при отработке функции foo1 переменная i инкрементируется, что и показывает вывод "I'm foo1 5", однако в поток ничего выведено не будет так как ссылки на него operator << с параметром foo2 еще возвращено не было.
Следовательно затем вызывается данный оператор и переменная i опять инкрементируется. Но снова ссылка на поток не доступна. Для ее получения требуется вызов последнего operator << с параметром возвращаемым foo3. На этом этапе переменная i опять инкрементируется и становиться равной 7. И вот наконец-то ссылка на поток получена и operator<< начинают отрабатывать. Сперва будет выведено значение возвращаемое foo3 т.е. 7, затем значение возвращаемое foo2 т.е. 6 и наконец значение возвращаемое foo1 равное 5.
2
1 / 1 / 0
Регистрация: 31.07.2014
Сообщений: 55
12.05.2016, 14:09  [ТС]
Спасибо большое, тему можно закрывать на ключик
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
12.05.2016, 21:43
Цитата Сообщение от Ilot Посмотреть сообщение
Сперва вызывается функция operator<< с аргументом возвращаемым функцией foo1. Однако известно, что функции члены принимают неявно первым параметром указатель this. Поэтому второй этап это получение ссылки this которая возвратиться при вызове operator << с параметром возвращаемым foo2 и т.д.
Ilot, вы троллите или серьезно? Что ж вы молодежь с панталыку сбиваете?
В выражении
C++
1
std::cout./**3*/operator<<(foo3())
функция operator<<(foo3()) получает указатель на то, что стоит слева от точки ./**3*/, т.е. на объект std::cout.
В выражении
C++
1
std::cout./**3*/operator<<(foo3())./**2*/operator<<(foo2())
функция operator<<(foo2()) получает указатель на то, что стоит слева от точки ./**2*/, т.е. на объект, который возвратит вызов функции std::cout./**3*/operator<<(foo3()) и т.д.
Вычисление же аргументов в обратном порядке объясняется все тем же: порядок вычисления аргументов любой неунарной операции (кроме логических, условного оператора и запятой) стандартом НЕ ОПРЕДЕЛЕН и в конкретной реализации выполняется так, как сочтут более удобным авторы этой реализации.
Операция точка (вызов функции-члена) в этом отношении не лучше любой другой. Порядок вычисления подвыражений слева и справа от этой точки тоже зависит от реализации.
В приведенном ниже примере в моей реализации функции вызываются слева направо, а их аргументы вычисляются справа налево:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
int     f_1()
{
    std::cout   <<  "f_1"
                <<  std::endl;
 
    return  0;
}
///////////////////////////////////////////////////////////////////////////////
int     f_2()
{
    std::cout   <<  "f_2"
                <<  std::endl;
 
    return  0;
}
///////////////////////////////////////////////////////////////////////////////
int     f_3()
{
    std::cout   <<  "f_3"
                <<  std::endl;
 
    return  0;
}
///////////////////////////////////////////////////////////////////////////////
struct  T_struct
{
    //-------------------------------------------------------------------------
    T_struct( int i )
    {
        ++i;
        std::cout   <<  "T_struct"
                    <<  std::endl;
    }
    //-------------------------------------------------------------------------
    T_struct    &    f( int i )
    {
        ++i;
        std::cout   <<  "f"
                    <<  std::endl;
 
        return  *this;
    }
    //-------------------------------------------------------------------------
    T_struct    &    g( int i )
    {
        ++i;
        std::cout   <<  "g"
                    <<  std::endl;
 
        return  *this;
    }
    //-------------------------------------------------------------------------
};
///////////////////////////////////////////////////////////////////////////////
int     main()
{
    T_struct( f_1() ).f( f_2() ).g( f_3() );
}
1
Эксперт по математике/физикеЭксперт С++
 Аватар для Ilot
2223 / 1425 / 420
Регистрация: 16.05.2013
Сообщений: 3,642
Записей в блоге: 6
13.05.2016, 07:37
Цитата Сообщение от Mr.X Посмотреть сообщение
Ilot, вы троллите или серьезно?
Я объяснил в каком порядке в данной ситуации происходят вызовы и почему и нигде не указал, что должно быть только так, а не иначе.
operator<< принимает два аргумента, а порядок передачи параметров в функцию как известно не определен. Поэтому сперва может быть может быть найден указатель на поток, а это приведет к тому, что вывод цифр будет последователен (5678). Возможны также и смешанные варианты.
Цитата Сообщение от Mr.X Посмотреть сообщение
В приведенном ниже примере в моей реализации функции вызываются слева направо, а их аргументы вычисляются справа налево:
Простите я правильно понял вывод в вашей реализации таков?
f_3
f_2
f_1
T_struct
f
g
И последнее. Впредь старайтесь, пожалуйста, быть более избирательным в выборе слов. Всегда можно вести дискуссию культурно.
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
13.05.2016, 08:38
Цитата Сообщение от Ilot Посмотреть сообщение
порядок передачи параметров в функцию как известно не определен.
Точнее, не определен порядок вычисления конкретных аргументов функции.
Цитата Сообщение от Ilot Посмотреть сообщение
Простите я правильно понял вывод в вашей реализации таков?
f_3
f_2
f_1
T_struct
f
g
Под реализацией я имею в виду конкретный компилятор. У меня в Qt creator тоже так как у вас выводит.

Когда в теме, где выше уже десять раз объяснено, что порядок вычисления аргументов функции не определен, человек, называющий себя экспертом, пытается доказать обратное, то первая мысль возникает, что он троллит. А вы бы что подумали?
Публикуя ошибочные суждения под видом истины, вы вводите читателей в заблуждение. Один из них даже пометил это ваше сообщение как ответ. Между прочим, эта метка до сих пор не снята, сделайте хоть сами это.
Если уж назвались экспертом, то полезайте в кузов, т.е. тщательнее обдумывайте свои сообщения, прежде чем публиковать.
0
Эксперт по математике/физикеЭксперт С++
 Аватар для Ilot
2223 / 1425 / 420
Регистрация: 16.05.2013
Сообщений: 3,642
Записей в блоге: 6
13.05.2016, 08:51
Цитата Сообщение от Mr.X Посмотреть сообщение
Под реализацией я имею в виду конкретный компилятор. У меня в Qt creator тоже так как у вас выводит.
И вот теперь поясните, что вы хотели доказать своим контр примером если последовательность вызова функций и передачи аргументов которую вы описали совпадает с той о которой я говорил в посте 11
Цитата Сообщение от Mr.X Посмотреть сообщение
А если серьезно, то когда в теме, где выше уже десять раз объяснено, что порядок вычисления аргументов функции не определен, человек, называющий себя экспертом, пытается доказать обратное, то первая мысль возникает, что он троллит. А вы бы что подумали?
Приведите цитату где я пытаюсь доказать обратное.
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
13.05.2016, 19:39
Цитата Сообщение от Ilot Посмотреть сообщение
Цитата Сообщение от Mr.X
Под реализацией я имею в виду конкретный компилятор. У меня в Qt creator тоже так как у вас выводит.

И вот теперь поясните, что вы хотели доказать своим контр примером если последовательность вызова функций и передачи аргументов которую вы описали совпадает с той о которой я говорил в посте 11

Цитата Сообщение от Mr.X
А если серьезно, то когда в теме, где выше уже десять раз объяснено, что порядок вычисления аргументов функции не определен, человек, называющий себя экспертом, пытается доказать обратное, то первая мысль возникает, что он троллит. А вы бы что подумали?

Приведите цитату где я пытаюсь доказать обратное.
Вам не кажется, что первое ваше утверждение в этом сообщении противоречит второму?
Между тем, метку "ответ" со своего ошибочного сообщения №11 вы так и не сняли, поэтому я не в силах воспринимать ваши сообщения серьезно. Судя по тому, что остальные эксперты вообще на это сообщение не реагируют, они уже все махнули на вас рукой. Последую и я их примеру.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
13.05.2016, 19:39
Помогаю со студенческими работами здесь

Запустить одну форму несколько раз
Добрый день, у меня есть форма 1, которая запускает форму 2, можно ли из формы один, за один раз запустить несколько раз форму 2, и в...

Построение отчета с перечисление результата в одну строку но в разные ячейки
День добрый. Прошу помощи, по VBA чайник. А при помощи одно SQL это не решить. Пример Бд приложил. Пытаюсь в итоге получить вот...

Как одну JLabel использовать несколько раз?
Добрые программисты помогите) У меня есть два текстовых поля heightField и widthField, а также одна метка JLabel с назв. meterLabel. В поле...

Цикл foreach обрабатывать одну операцию несколько раз
Помогите пожалуйста,не могу до думаться. У меня записывается в одну переменную несколько значений. Требуется применить одну и ту же...

Вывод результата определённое количество раз
Есть следующий код: domains x=integer i=integer k=integer predicates search(x,i,k) rez clauses


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru