Вопрос по c – Вывод printf («% d% d», c ++, c); тоже не определено?

20

Я недавно наткнулся на постКакой правильный ответ для cout & lt; & lt; с ++ & lt; & lt; с ;? и было интересно, есть ли выход

int c = 0;  
printf ("%d %d", c++, c);  

тоже не определено ??

Я изучал на лекциях, что постфиксные и префиксные операторы увеличивают значение только после получения точки с запятой. Так что по мне, выход0 0 верно !!!

возможный дубликатmultiple '++' working in variables, and pointers Pascal Cuoq

Ваш Ответ

6   ответов
2

ка оценки параметров. Вы можете доказать это "неопределенный вывод" делать некоторые случайные испытания:

printf("%d %d\n", c++, c);
// result: 0 1
printf("%d %d %d\n", c++, c, c++);
// result: 1 2 0
printf("%d %d %d %d\n", c++, c++, c++, c);
// result: 2 1 0 3
printf("%d %d %d %d\n", c++, c, c++, c);
// result: 1 2 0 2
printf("%d %d %d %d\n", c++, c, c, c);
// result: 0 1 1 1
Error: User Rate Limit ExceededcError: User Rate Limit Exceeded
1

неуточненное поведение а такженеопределенное поведение, Начиная сunspecified behavior,проект стандарта C99 в разделе6.5 параграф3 говорит:

The grouping of operators and operands is indicated by the syntax.74) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

Это также говорит, кроме как указано позже и конкретно цитируетfunction-call ()Итак, мы видим, что позже проект стандарта в разделе6.5.2.2 Function calls параграф10 говорит:

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

Таким образом, мы не знаем, является ли чтениеC или оценкаC++ произойдет первым в этой строке кода:

printf ("%d %d", c++, c); 

кроме того, в разделе6.5.2.4 Postfix increment and decrement operators параграф2 говорит:

[...] After the result is obtained, the value of the operand is incremented. [...] The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.

Итак, все, что мы знаем, это то, что при выполнении пост-приращенияc будет обновлено после прочтения его значения, но до следующеготочка последовательности что прямо передprintf называется, но больше ничего. Дляundefined behavior, если мы посмотрим на раздел6.5 параграф2 Исходя из проекта стандарта, говорится:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.

вprintf выражениеcСчитается предыдущее значение, чтобы оценить обаC++ а такжеC и вот мы сейчас вundefined территория.

19

t value only after getting a semicolon.

Отправь мне своего лектора, чтобы я могtake a baseball bat to him вежливо указать на свою ошибку.

Именно тогда, когда побочный эффект префикса или постфикса++ а также-- применяетсяunspecifiedкроме требования, чтобы это произошло перед следующей точкой последовательности. В выражении, как

x = a++ * b

a может быть обновлено сразу послеa++ была оценена, или обновление может быть отложено доa++ * b был оценен и результат назначенxили где-нибудь между.

Вот почему такие выражения, какi++ * i++ а такжеprintf("%d %d", c++, c) а такжеa[i++] = i и множество других - все плохо. Вы получите разные результаты в зависимости от компилятора, настроек оптимизации, окружающего кода и т. Д. Стандарт языка явно оставляет поведениеundefined так что компилятор не обязан «делать правильные вещи», какими бы правильными они ни были. Помните, определение дляundefined behavior является

3.4.3 1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

3 EXAMPLE An example of undefined behavior is the behavior on integer overflow.

Это преднамеренное проектное решение - обоснование для того, чтобы оставить порядок этих операций без указания, состоит в том, чтобы дать реализации возможность изменить порядок оценки для целей оптимизации. Однако в обмен на эту свободу некоторые операции не будут иметь четко определенных результатов.

Обратите внимание, что компилятор может свободноtry выявлять эти случаи и выдавать диагностику;printf("%d %d", c++, c); было бы достаточно легко поймать, но это было бы ошибкой, чтобы обнаружить в общем случае. Представьте, если бы это было написаноprintf("%d %d", (*p)++, c); еслиp указывает наcтогда поведение не определено, в противном случае все в порядке. Еслиp назначается в другой единице перевода, тогда во время компиляции невозможно узнать, является ли это проблемой или нет.

Эту концепцию нетрудно понять, но она является одной из самых непонятных (и неверно понятых).taught) аспекты языка Си. Несомненно, именно поэтому спецификации языка Java и C # устанавливают определенный порядок оценки для всего (все операнды вычисляются слева направо, и все побочные эффекты применяются немедленно).

Error: User Rate Limit Exceeded
6

t value only after getting a semicolon

Это не то, как стандарт описывает это.точка последовательности это точка в коде, в которой были оценены побочные эффекты, которые могли возникнуть в предыдущих частях кода. Запятая между аргументами функции не является точкой последовательности, поэтому ее поведение не определено.

Порядок вычисления аргументов функции не определен. Нет гарантии, что аргументы функции будут оцениваться в порядке(1, 2, N), поэтому нет гарантии, что приращение будет оценено перед передачей второго аргумента.

So according to me, the output 0 0 is correct !!!

Нет, поведение не определено, поэтому вы не можете обоснованно утверждать, что на выходе будет 0 0.

Error: User Rate Limit Exceeded Snehasish
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Snehasish
Error: User Rate Limit Exceeded Snehasish
Error: User Rate Limit Exceeded
1

это не определено. Причина в том, что, хотя и гарантируется, что три аргументаprintf() будет оцениваться раньшеprintf() вызывается, последовательность, в которой оцениваются три аргумента, не определена.

Технически неверно, что увеличение происходит только после точки с запятой, между прочим. Стандарт гарантирует, что приращение произойдет не позднее точки с запятой. [На самом деле, в вашем случае, я считаю, что стандарт гарантирует, что это произойдет до того, как контроль будет переданprintf() функция - но теперь этот ответ начинает раскручиваться в царство педантичных мелочей, так что позвольте мне остановиться здесь!]

Короче говоря, вы правы. Поведение не определено.

Update:  Как справедливо замечает @R .., неопределенное поведение происходит из-за отсутствия точки последовательности между аргументами. Стандарт довольно осторожен в отношении причастийunspecified а такжеundefined, поэтому исправление принято с благодарностью.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededC.
Error: User Rate Limit Exceededsequence point.Error: User Rate Limit Exceeded
3

поскольку оно нарушает требования 6.5 выражений:

Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.

c++ а такжеc оба оцениваются без промежуточной точки последовательности и предыдущего значенияc читается как для определения значения, которое будет сохраненоc++и определить значение выраженияc.

Похожие вопросы