Результат int c = 0; соиЬ << С++ << с;
Я думаю, что это должно быть 01, но кто-то говорит его "undefined", любая причина для этого?
Ответы
Ответ 1
c++
- это как приращение, так и назначение. Когда происходит присвоение (до или после другого кода в этой строке), остается до усложнения компилятора. Это может произойти после cout <<
или раньше.
Это можно найти в стандарте C99
http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf
Вы можете найти его на стр. 28 в pdf или разделе 5.1.2.3
фактическое приращение p может происходить в любое время между предыдущей точкой последовательности и следующей точкой последовательности
Так как кто-то попросил стандарт С++ (так как это вопрос на С++), его можно найти в разделе 1.9.15 стр. 10 (или 24 в формате pdf)
оценки операндов отдельных операторов и подвыражений отдельных выражений не подвержены последовательности
Он также включает следующий блок кода:
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
Я чувствую, что стандартное объяснение C99 более ясное, но оно верно на обоих языках.
Ответ 2
Это поведение undefined, если вы изменяете значение, а затем читаете его (или пытаетесь изменить его снова) без промежуточной точки последовательности. Понятие точки последовательности в С++ немного технически (вы можете немного прочитать об этом здесь), но в итоге это поток inserting (<<
) не является точкой последовательности.
Причина, по которой это поведение undefined заключается в том, что в отсутствие точки последовательности компилятору разрешено выполнять переопределение операций любым способом, который он считает нужным. То есть, разрешено извлекать значение c
(и удерживать его для второй вставки), а затем выполнить послесловие c++
, чтобы получить значение для первой вставки. Таким образом, вы не можете быть уверены, произойдет ли приращение до или после значения c
для второй вставки.
Ответ 3
Поведение определено, но неопределено. Относительный порядок оценки двух видов использования "c" в выражении не указан. Однако, если вы преобразуете его в функциональную нотацию, это выглядит так:
cout.operator<<(c++).operator<<(c);
Существует точка последовательности между оценкой аргументов функции и выполнением тела функции, а тела функций не чередуются, поэтому результат является только неопределенным, а не undefined.
Если у вас не было перегруженного оператора:
int c=0;
int a = c++ << c;
Тогда поведение будет undefined, потому что и модификация и использование значения c
без промежуточной точки последовательности.
Изменить: последовательность litb
возникает просто неправильно. В стандарте указывается (§1.9/17): "При вызове функции (независимо от того, является ли функция встроенной), после оценки всех аргументов функции (если они есть) есть точка последовательности, которая имеет место перед выполнением любых выражений или операторов в теле функции."
Это ясно написано с мыслью, что аргументы оцениваются, затем (сразу после этого) выполняется тело функции. Последовательность, которую он предлагает, в которой оцениваются аргументы одной функции, затем аргументы другому, тогда выполнение обоих тел функций, похоже, не предназначено, но также не запрещено. Это, однако, ничего не меняет - требование все еще таково: "... после оценки всех аргументов функции (если они есть) есть точка последовательности..."
Последующий язык о выполнении тела НЕ удаляет требование для точки последовательности после оценки всех аргументов функции. Вся последующая оценка, будь то из тела функции или других аргументов функции, следует этой точке последовательности. Я могу быть настолько педантичным и извращенным, как и кто-то, кто неправильно читает то, что явно предназначено (но не совсем сказано), - но я не могу представить, как "точка последовательности после оценки всех аргументов функции" может быть прочитана как значение "после оценки всех аргументов функции нет точки последовательности".
Точка Neil, конечно, правильная: синтаксис, который я использовал выше, предназначен для функций-членов. Для не-членной перегрузки синтаксис будет больше похож:
operator<<(operator<<(cout,c++), c);
Это не устраняет требования для точек последовательности, хотя.
Насколько он неуточнен: это довольно просто: есть точка последовательности после оценки всех аргументов функции, поэтому все аргументы для одного вызова функции должны быть полностью оценены (включая все побочные эффекты), затем аргументы для другой функции вызов может быть оценен (с учетом любых побочных эффектов от другого) - НО нет требования о том, какие аргументы вызова функции WHICH должны оцениваться первым или вторым, поэтому это может быть c
, затем c++
, или это может быть c++
, тогда c
- но это должно быть одно или другое, а не чередование.
Ответ 4
Причина, по которой это undefined, заключается в том, что компилятор может свободно вычислять функциональные параметры в любом порядке. Рассмотрим, если вы вызываете функцию (потому что вы есть, но ее легче представить, когда она находится в синтаксисе функций):
cout.output(c++).output(c);
Компилятор может поражать параметры в обратном порядке, в прямом порядке или что угодно. Он может вызывать первый вывод перед вычислением параметра ко второму выходу, либо он может выполнять оба действия, а затем вызывать.
Ответ 5
Как я вижу, F (С++);
эквивалентно: е (с); c + = 1;
А F (С++, С++);
эквивалентно: е (с, с); c + = 1; c + = 1;
Но может случиться так, что F (С++, С++);
становится F (C, C + 1); c + = 2;
Эксперимент с gcc и clang, сначала в C
#include <stdio.h>
void f(int a, int b) {
printf("%d %d\n",a,b);
}
int main(int argc, char **argv) {
int c = 0;
f(c++,c++);
return 0;
}
и в С++
#include <iostream>
int main(int argc, char **argv) {
int c = 0;
std::cout << c++ << " " << c++ << std::endl;
return 0;
}
Интересно, поскольку gcc и g++ скомпилировали результаты в 1 0
тогда как clang скомпилировал результаты в 0 1