2013-11-01 2 views
0
#include<stdio.h> 
int main() 
{ 
    int i=2; 
    printf("%d %d \n",++i,++i); 
} 

Приведенный выше код дает выход 4 4. Может ли кто-нибудь помочь, как объяснить выход?Неожиданная работа printf() в C

+1

Это неопределенное поведение. См., Например, здесь http://stackoverflow.com/questions/19694756/how-pre-and-postfix-are-evaluated-in-printf – jaap

ответ

1

Это связано с точками последовательности, и это может привести к неопределенному поведению.

Прямо из Википедии:

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

Больше информации здесь: http://en.wikipedia.org/wiki/Sequence_point

2

++ я это приращение префикса. Printf сначала должен оценить свои аргументы перед их печатью (хотя в каком порядке он не гарантируется и, строго говоря, не определен - см. Запись Wiki в Undefined Behavior: http://en.wikipedia.org/wiki/Undefined_behavior).

Приращение префикса называется «приращением и выборкой», то есть оно сначала увеличивает значение, а затем передает его вызывающему.

В вашем случае i был сначала увеличен в два раза, и только после этого выход был отформатирован и отправлен на консоль.

+0

Как этот ответ получил голос? 'in func (a, a ++), не является оператором запятой, его просто разделителем между аргументами a и a ++. Поведение не определено в этом случае, если a считается примитивным типом) ' – Sadique

+0

@Acme Я проголосовал за это, он вообще не упоминает оператора запятой? Но в нем упоминается тот факт, что это просто вызов функции, и что вызовы должны оценивать все свои аргументы перед выполнением фактического вызова, который, похоже, указывает на то, что запутывает OP. – unwind

+0

@unwind - Существует тонкая разница в том, что вы говорите и в ответе. Ответ заключается в том, что порядок оценки неуточнен, что является правильным, но не упоминает, что это UB. Это 'в вашем случае, я был сначала увеличен дважды, и только потом результат был отформатирован и отправлен на консоль.' Неверно. Этот 'printf («% d% d \ n », ++ i, ++ i);' является четким разрезом UB. Сначала будет оценен этот ''% d% d \ n "', этот '++ i' или этот' ++ i' - подумайте об этом. – Sadique

0

Оба ответа совершили ту же ошибку. Его четкое сокращение UB, а не просто неуказанное поведение.

Что вы испытали - Undefined behavior. Пожалуйста, прочитайте о точках последовательности. Comma - это разделитель в вызовах функций, а не оператор.

Точка последовательности - это момент времени, в течение которого пыль оседает, и все побочные эффекты, которые были замечены до сих пор, гарантированы. Точки последовательности, перечисленные в стандарте C являются:

в конце оценки полного выражения (полное выражение является выражением личных данных, или любое другое выражение, которое не является Подвыражение в пределах любого большего выражения); на ||, & &,?:, И операторы запятой; и при вызове функции (после оценки всех аргументов и непосредственно перед фактическим вызовом).

Стандарт утверждает, что

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

Что будет оцениваться первым этой "%d %d \n", это ++i или это ++i (второй) - думать об этом.Это было бы не определено поведение:

void f(int x) 
{ 
    printf("%d ",x); 
} 
int main() 
{ 
    int i=0; 
    f(i++) ; 
} 

Из вики:

Перед тем, как функция вводится в вызове функции. Порядок, в котором оцениваются аргументы , не указан, но эта точка последовательности означает, что все их побочные эффекты завершены до ввода функции . В выражении f (i ++) + g (j ++) + h (k ++) f называется с параметром исходного значения i, но i приращается перед входом в тело f. Аналогично, j и k обновляются до , входящих в g и h соответственно. Однако не указано, в каком порядке выполняются порядок f(), g(), h(), и в каком порядке i, j, k равны . Переменные j и k в теле f могут иметь или не иметь , которые уже были увеличены. Обратите внимание, что вызов функции f (a, b, c) не является использованием оператора запятой, а порядок оценки для a, b и c не указан.

Смежные вопросы