stranni razliki v C

9 отговора 502 прегледа
#1

stranni razliki v C

kak obiasnuiavate razlikata v slednia kod:

1. a=20;
printf("%d\n",a+(a++)+(a>3));

2. a=20;
printf("%d\n",(a>3)+a+(a++));

purviat sluchaj dava 42 pri Linux i 41 pri Windows
vtoria 41 pri Linux i 42 pri Windows

i tva, samo ako vaprosnata operacia e nekakvo sravnenie. v tozi sluchaj e razlichno:

1. a=20;
printf("%d\n",a+(a++)+(a-19));

2. a=20;
printf("%d\n",(a-19)+a+(a++));

purviat sluchaj dava 41 pri Linux i 41 pri Windows
vtoria 41 pri Linux i 43 pri Windows

napravo uzas ;-)

Редактирано от Milenn на

Отговор
в отговор на Milenn #2

Re: stranni razliki v C

Абе не е само при сравнение, и при останалите операции го има това. Както се казваше в една книжка на Пратчет - Всичко е ОК, пич.

Значи разногласието идва не от ОС-а, а от компилаторите дето ползваш. Трябва да RFM на компилатора, за да провериш дали чете операторите отляво надясно, или отдясно наляво. Конфликтът идва от това, че в самия език не е определена твърдо посоката на четене, и авторите на компилатори сами я определят. Всъщност повечето компилатори май имат опция за указване на посоката.

Та, проблемът е че операцията ++ се изпълнява не след точкозапетаята, а след като бъде използвана променливата. И така, когато имаш:

printf("%d\n",(a-19)+a+(a++));

В посока дясно, ще увеличиш "а" след като си го ползвал като 20 навсякъде и резултатът е 41, в посока ляво, ще имаш:
1) 20 ++
+
2) 21
+
3) 21-19=2

или общо 20+21+2 = 43.

В случая когато ++ ти е в средата, ползваш променливата по равен брой пъти увеличена. Подобна е и ситуацията при сравняването.

Имахме преди време същия проблем, като направихме copy+paste от gcc във VS6.0. За да избегнеш проблема, трябва да имаш еднозначност и в двата случая, така че когато ползваш два пъти една променлива просто изкарай ++ като отделна операция, съответно преди или след изчислението.

Няма проблеми.

Бтв, имаше една подобна залъгалка, кажи как ще разчете компилатора това:
a = b +++ c;

Мечтата е мисъл, мисълта е идея, всяка идея се реализира. Аз не мечтая, а реализирам идеите си.
Отговор
в отговор на Duncan Griffin #3

Re: stranni razliki v C

hm... reda uz e opisan oste ot Kerningan i Ritchie, pone go ima v knigata im.
c=a+++b nema nikakvo dvusmislie, ++ ima po-visok prioritet ot + i zatova se izcisliava purvo, probvah go na 3 compilatora. osven tva sas skobi se promena reda bez problem, dokato v mojata glavobluskanica izglezda savsem razlichno i alogichno
zabelezi che imam skobi navsekade, i 3 sabiraemi. spored komutativnia zakon ne bi trebvalo da ima razlika. oste poveche sled kato ++ e na poslednata pozicia
obratnoto , kakto e vav TC po go razbiram nekak si. izobshto ne mi e iasno, zashto se izpulnava ++

vsustnost, sled dosta opiti veche pochti razbrah zashto, ste se probvam oste s nekolko varianta i ste kaza do kakyv izvod sam stignal. zasega izglezda che ++ ima prioritet i pred skobite

Отговор
в отговор на Milenn #4

ех че интересно :)

значи аз досега си мослех че ++ се изпълнява след точката и запетаята, но след твоя постинг се отказвам публично да го ползвам дори в изрази като
a=b+c++;
вече ще пиша само:
a=b+c;
c++;

а иначе предполагам точно заради скобите ++ се изпълнява преди това, защото компилатора явно си мисли че щом е излязъл от скобите, значи може да го инкрементира :))))
аз до миналата седмица писах разделено инкрементирането, и тъкмо се наканих да ползвам инкрементиране в израза, та сега пак се връщам на разделеното.

Отговор
в отговор на Milenn #5

Re: stranni razliki v C

Каквито и закономерности да намериш те ще са валидни за конкретната реализация на компилатора. Ето например какво пише в GCC Manual

* Making side effects happen in the same order as in some other compiler.

It is never safe to depend on the order of evaluation of side effects. For example, a function call like this may very well behave differently from one compiler to another:

void func (int, int);

int i = 2;
func (i++, i++);


There is no guarantee (in either the C or the C++ standard language definitions) that the increments will be evaluated in any particular order. Either increment might happen first. func might get the arguments 2, 3, or it might get 3, 2, or even 2, 2.

Отговор
в отговор на Milenn #6

Re: stranni razliki v C

izvoda e ce kato se naloji da se pise na C trebva da se slagat vinagoi skobi!
inace pravi kvoto si iska!
az kato napisa nesto gledam kav kod e generiralo za da sam siguren ce sa raboti kakto trebva! ebasi i ezika! (stava vapros za kompilatora na KEIL za 8051)

Отговор
в отговор на CALL-151 #7

Re: stranni razliki v C

Приятел, скобите в случая никва файда нямат.
Това си е класически "undefined behaviour" и във всяка по-сериозна книжка го има като пример. "shoro" вече добре е обяснил за какво става дума.

Отговор
в отговор на CALL-151 #8

Re: stranni razliki v C

Edno vreme tozi kompilator go karah da mi prvi listing file i posle go preglejdah, obache ne za da mu tarsya greshki (towa e mazohizam (s tozi indexen access za xdata...)) ami za da vidya kakvo moje da se optimizira (da, nalaga se, ako imash i RTX51 deto da ti smuche resursite). Ne sam zabelyazal da pravi nyakakvi strahotni gluposti. (osven towa KEIL C ne e tochno C, a neshto kato extension na C za 8051, koito ot swoya strana e edin mnoooo shiban procesor :))

Отговор
в отговор на Milenn #9

Не се занимавай с глупости

Такъв код не става задника да си избършеш с него, така че не трябва да ти пука какво прави. Премини детския етап и пиши смислен код.


System Doctor Error:
Your girlfriend is pregnant.
(A)bort, (M)arry, (I)gnore?_
Отговор
в отговор на Milenn #10

Re: stranni razliki v C

Аз лично не виждам "udefined behaviour" в предоставеното парче код:
Windows, VC++ - написания по-долу код винаги дава 41 и при f1() и при f2():
------------------------------------------
void f1(int a)
{
printf("%d\n", a + (a++) + (a > 3));
}

void f2(int a)
{
printf("%d\n", (a > 3) + a + (a++));
}

int main()
{
int a = 20;
f1(a);
f2(a);
return 0;
}
------------------------------------------
Оператора postincrement ++ в случая винаги се изпълнява, след като е използвана стойността на променливата в израза.
------------------------------------------
Ако printf() беше извикана с 2 параметъра и в двата се правеше а++, тогава бихме могли да говорим за "behaviour", зависещ от реда на поставяне на параметрите в стека.

Отговор