IT şi electronică > Programare
problema cu operatii pe biti
automat:
Salut.
Am gasit o problema pe care sa mor daca o inteleg.
In cazul operatiei pe biti nu inteleg de rezultatul este : 32
i=i<<3 este 8, mai departe ....
In cazul primului printf daca b=3 ; b++ este 3
b++ este 4
++b este 6
#include<stdio.h>
int main()
{
int i=1;
int a=5, b=3;
i=i<<3+i<<1;
printf("\n %d \n", i);
printf("\n %d %d %d\n", ++a, a++, a++);
printf("\n %d %d %d\n", b++, b++, ++b);
}
Pozitron:
@automat: Esti rugat sa pui titluri mai sugestive topicelor deschise aici. Daca mai gasesc topice cu titlul "problema" si atat, le voi muta la cosul de gunoi.
<Pozitron>
AlexandruLazar:
Rezultatul operaţiilor pe biţi este un caz de precedenţă a operatorilor. Operatorii de deplasare pe biţi (<< şi >>) au prioritate mai mică decât cei aritmetici (+, - etc.), iar asociativitatea lor este de la stânga la dreapta. Astfel încât i = i << 3 + i << 1 se evaluează ca i = ( i << (3 + i) ) << 1 . Operatorul "=" are prioritatea cea mai mică din expresia asta, deci atribuirea se evaluează ultima.
Acum dacă i = 1, înseamnă că avem i = (1 << 4) << 1, deci i = 16 << 1 care dă 32.
Vezi aici (include şi operatorii C, şi cei din C++).
Primul printf e un caz de comportament nedefinit:
--- Citat ---When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all function arguments (if any) which takes place before execution of any expressions or statements in the function body. There is also a sequence point after the copying of a returned value and before the execution of any expressions outside the function.
--- Terminare citat ---
Un sequence point este un punct din execuţia programului în care este garantat faptul că toate modificările unor variabile datorate unor expresii anterioare au fost efectuate, şi nicio modificare datorată unei expresii care nu a fost încă evaluate nu se află în desfăşurare. De exemplu, în printf("%d", ++a), există un sequence point după evaluarea argumentelor funcţiei ("%d", respectiv ++a), iar apelul este legal şi previzibil -- atunci când execuţia funcţiei printf() începe, e garantat faptul că ++a a fost evaluat iar valoarea lui a a fost schimbată.
Regula pentru ca o operaţie să nu fie ambiguuă este că o variabilă să fie modificată o singura dată între două sequence point-uri. Un apel de tipul printf("%d %d", ++a, a++) este ambiguuă pentru că, deşi există un sequence point după evaluarea argumentelor lui printf, până să ajungi la el încerci de două ori să modifici valoarea lui a. Virgula din apelul unei funcţii nu este operatorul binar ",": ordinea evaluării argumentelor unei funcţii nu este specificată.
Ca idee, la primul printf eu am obţinut "8, 6, 5", iar la al doilea "5, 4, 6".
Adi:
Ce itneresant ca se dezbate acest subiect aici. Folosim astfel de operatii pe biti in codul nostru in fizica particulelor pentru a putea modela intr-un singur numar (o insiruire de 0 si 1) daca un eveniment (o fotografie de coliziuni de particule) trece sau nu fiecare din insiruirea de criterii dorite pentru selectarea evenimentelor. Si chiar am de facut un programel care sa introduca asta, dupa ce cred ca am gasit o formula draguta saptamana trecuta. Am citit atunci o zi intreaga pe Wikipedia despre operatii pe biti.
http://en.wikipedia.org/wiki/Bitwise_operation
MariS:
int i=1;
int a=5, b=3;
i=i<<3+i<<1;
printf("\n %d \n", i);
printf("\n %d %d %d\n", ++a, a++, a++);
printf("\n %d %d %d\n", b++, b++, ++b);
Corect raspunsul lui Alexandru Lazar. Eu am primit un rezultat un pic diferit:
32
8 6 5
5 4 4
Cu 32 s-a lamurit foarte bine de Alexandru. De ce 8 6 5? Se observa ca argumentele au fost evaluate de la dreapta la stanga: ultimul argument este postincrementat, deci se printeaza cu vechea valoare, adica 5, apoi se incrementeaza si devine 6. Argumentul mijlociu e tot postincrementat, dar fiind evaluat dupa cel ultim va primi valoarea incrementata de la acesta, adica 6, si pe asta o printeaza, dupa care o incrementeaza si el, valoarea lui "a" devenind 7. Iar primul argument, fiind preincrementat, ridica intai valoarea la 8 si apoi o printeaza.
La linia urmatoare, evaluarea e la fel de la dreapta la stanga: ultimul argument e preincrementat si il ridica pe "b" la 4, il printeaza, apoi mijlociul e postincrementat, deci intai printeaza 4 si apoi il ridica la 5 dupa care vine si primul argument care, fiind tot postincrementat va printa mai intai valoarea 5 si abia apoi o va incrementa. Dar, atentie, doar evaluarea argumentelor se face de la dreapta la stanga, printarea lor, totusi, se executa bine incepand cu primul.
Dar e posibil ca rezultatul sa fie diferit daca evaluarea argumentelor functiei se face de la stanga la dreapta. Aici se face un abuz de "elasticitate" sau "libertate" oferita de limbajul C, care e foarte generos in aceasta privinta, si nu e recomandat un astfel de mod de programare.
Navigare
[#] Pagina următoare
Du-te la versiunea completă