унарные операторы в printf

Может ли кто-нибудь объяснить мне вывод следующего. Я попытался все обосновать и могу объяснить более позднюю часть, где «x» присваивается значение выражения, но не могу понять, чем отличается ответ в операторе printf !!!

Разные компиляторы могут вести себя по-разному. Было бы здорово, если бы кто-нибудь мог объяснить такое поведение для любого компилятора.

Я использую gcc (SUSE Linux) 4.6.2 на openSUSE 12.1 (Asparagus) (i586)

код :

#include<stdio.h>

int main()
{
unsigned int x=0;
printf("expr= %d x=%d\n",(x^x),x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",(x^x)||x++,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",(x^x)||x++||++x,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",(x^x)||x++||++x||x++,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",x++,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",++x||x++,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",x++||++x||x++,x);
printf("x=%d\n",x);
x=0;
printf("expr= %d x=%d\n",(x^x)||x++||++x||x++,x);
printf("x=%d\n",x);
x=0;
(x^=x);
printf("x=%d\n",x);
x=0;
(x^=x)||x++;
printf("x=%d\n",x);
x=0;
(x^=x)||x++||++x;
printf("x=%d\n",x);
x=0;
(x^=x)||x++||++x||x++;
printf("x=%d\n",x);

return 0;
}

выход :

expr= 0 x=0
x=0
expr= 0 x=1
x=1
expr= 1 x=2
x=2
expr= 1 x=2
x=2
expr= 0 x=1
x=1
expr= 1 x=1
x=1
expr= 1 x=2
x=2
expr= 1 x=2
x=2
x=0
x=1
x=2
x=2

Спасибо


person ntalli    schedule 25.01.2012    source источник
comment
Это много кода. Пожалуйста, укажите, какие из них вы не понимаете (еще лучше, просто удалите все те, которые вы понимаете).   -  person Oliver Charlesworth    schedule 26.01.2012
comment
Я постоянно поражаюсь количеству людей, которые хотят предварительно и после увеличения переменной между точками следования... почему?   -  person Ed S.    schedule 26.01.2012
comment
@EdS.: || - это точка последовательности.   -  person Oliver Charlesworth    schedule 26.01.2012
comment
@OliCharlesworth: Ха-ха, как я пропустил все это? :D Похоже, Дэвид тоже.   -  person Ed S.    schedule 26.01.2012
comment
Да, я только что прочитал (x^x)||x++||++x||x++ и среагировал инстинктивно.....   -  person David Heffernan    schedule 26.01.2012
comment
Для OP, дайте эту ссылку прочитать. susam.in/blog/sequence-points   -  person Abhijeet Rastogi    schedule 26.01.2012
comment
@oli: скажем так, меня смущают два сценария: x=0; printf(expr= %d x=%d\n,(x^x)||x++||++x||x++,x); printf(x=%d\n,x); и х=0; (х^=х)||х++||++х||х++; printf(x=%d\n,x);   -  person ntalli    schedule 26.01.2012
comment
@shadyabhi: я понимаю беспокойство, и я не фанат этих маленьких трюков. Хотя мне просто любопытно, как подойти к этим вопросам с учетом любого типа компилятора, скажем, gcc 4.6.2 (я использую opensuse 12.1, i586)   -  person ntalli    schedule 26.01.2012
comment
@user1170267 user1170267 Я не информировал вас о трюках. Это не мой блог. Я просто нашел это полезным. Это объясняет концепцию, используя ссылки из The Standard и таких книг, как K&R. Итак, просто захотелось поделиться.   -  person Abhijeet Rastogi    schedule 26.01.2012
comment
Это один из тех вопросов, когда вы хотите знать, что делает ваш конкретный компилятор, но не заботитесь о том, что код будет вести себя иначе на других компиляторах?   -  person David Heffernan    schedule 26.01.2012
comment
@David: Этот код может быть несогласованным для разных компиляторов, но для поведения должны быть какие-то рассуждения более высокого уровня. В конце концов, компиляторы следуют одним и тем же стандартам. Когда я увидел этот фрагмент кода, мне стало любопытно, и я попробовал разные перестановки, как вы можете видеть в коде, но я так и не уловил разницы в поведении одного и того же выражения в printf по сравнению с присваиванием.   -  person ntalli    schedule 26.01.2012
comment
Поскольку вы спрашиваете о своем конкретном компиляторе, вы должны сказать, что это такое в вопросе   -  person David Heffernan    schedule 26.01.2012
comment
Извините, я новичок на этом форуме. Я отредактирую вопрос и позабочусь об этом в следующий раз.   -  person ntalli    schedule 26.01.2012


Ответы (2)


Вы вызываете неопределенное поведение.

В таком выражении, как func(a,b), стандарт C не определяет, какой аргумент должен оцениваться первым; компилятор может делать и то, и другое.

Итак, теперь рассмотрим func(x++,x); не указано, эквивалентно ли это этому:

a = x++;
b = x;
func(a,b);

или это:

b = x;
a = x++;
func(a,b);
person Oliver Charlesworth    schedule 25.01.2012
comment
По этой причине у меня также есть printf(%d\n,x) после каждого printf(expr=%d x=%d,'expr',x) только для того, чтобы подтвердить то же самое. Похоже, вывод согласован. - person ntalli; 26.01.2012

printf("expr= %d x=%d\n",(x^x)||x++||++x,x);

Эта функция показывает неопределенное поведение. Порядок оценки между (x^x)||x++||++x и x не указан.

Большинство других вызовов printf в вашей программе имеют ту же проблему.

(C99, 6.5.2.2) «Порядок оценки указателя функции, фактических аргументов и подвыражений в фактических аргументах не указан, но перед фактическим вызовом есть точка последовательности».

Программа, вывод которой зависит от неопределенного поведения, не является строго соответствующей программой (см. C99, 4.p5).

person ouah    schedule 25.01.2012
comment
По этой причине у меня также есть printf(%d\n,x) после каждого printf(expr=%d x=%d,'expr',x) только для того, чтобы подтвердить то же самое. Похоже, вывод согласован. - person ntalli; 26.01.2012
comment
@user1170267 user1170267 вывод может соответствовать вашему компилятору, но, поскольку это неуказанное поведение, он может отличаться от другой версии того же компилятора или даже отличаться от того же компилятора, но в другой день недели. - person ouah; 26.01.2012
comment
скажем, меня интересует только printf(expr= %d\n,(x^x)||x++||++x||x++) ..... и (x^=x)||x++| |++x||x++) на данный момент. - person ntalli; 26.01.2012
comment
@user1170267 user1170267 printf("expr= %d\n",(x^x)||x++||++x||x++); не является неопределенным поведением и строго соответствует требованиям. - person ouah; 26.01.2012