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

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

12.05.2016, 00:31. Показов 6205. Ответов 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
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,217
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
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru