почему функция printf показывает желаемый результат в следующем коде?

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
    int a=1;
    printf("%d\t%d\t%d\n",a,++a,a++);
    return 0;
}

Почему вывод кода 3 3 1. кто-нибудь объяснит мне, как происходит такой вывод?


person play store    schedule 17.06.2019    source источник
comment
@BattleTested - cstdio мне кажется заголовком C++.   -  person StoryTeller - Unslander Monica    schedule 17.06.2019
comment
@play store. Разве вы не получали предупреждение вроде этого: предупреждение: модификация без последовательности и доступ к 'a' [-Wunsequenced]?   -  person Vishaal Shankar    schedule 17.06.2019
comment
@StoryTeller Да, вы правы....   -  person BattleTested_закалённый в бою    schedule 17.06.2019


Ответы (2)


Похоже, ваш компилятор читает параметры справа налево

printf("%d\t%d\t%d\n",a,++a,a++); // a = 1

a++ возвращает a и увеличивает его на 1

printf("%d\t%d\t%d\n",a,++a, 1); // a = 2

++a увеличивает a на 1 и возвращает результат

printf("%d\t%d\t%d\n",a, 3, 1); // a = 3

а это просто

printf("%d\t%d\t%d\n", 3, 3, 1); // a = 3

Но, насколько мне известно, это своего рода UB, потому что стандарт С++ не определяет, в каком порядке считываются параметры, поэтому я бы не стал делать ставку на то, что он будет одинаковым для разных компиляторов.

Изменить: с С++ 17 это больше не UB, а не указано. Вы все равно должны избегать этого

person Narase    schedule 17.06.2019
comment
см. комментарий от StoryTeller под моим ответом. Это уже не всегда UB. В С++ 17 это не указано. - person Tarick Welling; 17.06.2019
comment
Я прочитал это. Но unspecified чуть лучше, чем UB. Также следует избегать конкретных реализаций компилятора. - person Narase; 17.06.2019
comment
полностью согласен, но ваш ответ становится лучше, когда он включен :) - person Tarick Welling; 17.06.2019
comment
Ваши последние 2 абзаца можно немного перефразировать. Когда есть UB, это не просто означает, что вы оцениваете их в непредсказуемом порядке, но UB — это то, что компилятор может предположить, что никогда не произойдет, поэтому до C++ 17 не только результат не определен, но и весь код мог делать что угодно, с C++17 вы все еще не знаете порядок, но нет UB, что является принципиальным отличием - person 463035818_is_not_a_number; 17.06.2019

Это неопределенное поведение в соответствии с порядком оценки. ссылка (см. главу Неопределенное поведение)

Результат:

3 3 1

потому что он оценивается следующим образом:

a++
используйте a(1) и a становится 2
++a
a становится 3 и используйте a(3)
используйте a(3)

Важно знать, что a++ является постинкрементным, а ++a — преинкрементным. Постинкремент означает: использовать значение и увеличивать его после. Предварительное приращение означает: увеличить значение и использовать увеличенное значение.

примечание: С++ 17 изменил это поведение с неопределенного на неопределенное, но в предыдущих версиях это все еще неопределенное поведение.

person Tarick Welling    schedule 17.06.2019
comment
Вам следует более внимательно прочитать раздел (начиная с C++17). Это уже не UB, просто не указано. - person StoryTeller - Unslander Monica; 17.06.2019
comment
страница cppreference немного расплывчата по этому поводу. (лично я не вижу раздела C++17), но на самом деле это уже не UB. Есть ли у вас обновленная документация по порядку оценки в С++ 17? - person Tarick Welling; 17.06.2019
comment
Легко пропустить упоминание C++17 на мобильных устройствах. Во всяком случае, в самой ссылке, на которую вы ссылаетесь, есть множество примеров, в которых говорится о неопределенном поведении до С++ 17. - person StoryTeller - Unslander Monica; 17.06.2019
comment
Глупый я, я ожидал где-то с С++ 17, но, конечно, оператор unspecified - это вся документация, необходимая для этого. - person Tarick Welling; 17.06.2019