#include /* Program demonstrira koriscenje bitovskih operatora za ocitavanje i prikaz binarnog zapisa podataka razlicitih tipova */ /* Funkcija prikazuje bitove binarnog zapisa neoznacenog broja x */ void prikazi_unsigned(unsigned x){ unsigned maska = 1 << 31; while(maska){ putchar(x & maska ? '1' : '0'); maska >>= 1; } } typedef union { float f; unsigned d; } FD; /* Funkcija prikazuje bitove binarnog zapisa realnog (float) broja x koristeci se unijskim tipom (bitovski operatori se mogu primeniti samo nad celobrojnim tipovima) */ void prikazi_float(float x){ FD fd; fd.f = x; /* Upisujemo realnu vrednost u uniju */ /* Sada taj isti binarni sadrzaj tumacimo kao unsigned */ prikazi_unsigned(fd.d); } /* Drugi nacin je da se izvrsi konverzija pokazivaca. Prilikom konverzije float * --> unsigned * adresa se ne menja, ali se menja tumacenje podatka na koji pokazivac pokazuje. Na ovaj nacin se float prosto tumaci kao da je unsigned, bez konverzije */ void prikazi_float2(float x){ prikazi_unsigned(*(unsigned *)&x); } typedef union { double lf; unsigned d[2]; } LFD; /* Funkcija prikazuje bitove binarnog zapisa realnog (double) broja x koristeci unijski tip */ void prikazi_double(double x){ LFD lfd; lfd.lf = x; /* Upisujemo realnu vrednost u uniju */ /* Ispisujemo bitove double-a tumaceci ga kao dva unsigned-a. Najpre ispisujemo visa 32 bita, a zatim niza 32 bita */ prikazi_unsigned(lfd.d[1]); prikazi_unsigned(lfd.d[0]); } /* Alternativno, mozemo koristiti tip unsigned long long (uveden u C standard 99-te godine) koji je uvek sirine 64 bita (za razliku od unsigned long-a koji na 32-bitni operativnim sistemima ima sirinu 32 bita, dok na 64-bitnim operativnim sistemima ima sirinu 64 bita). */ typedef union { double lf; unsigned long long d; } LFLD; /* Funkcija prikazuje bitove podatka tipa unsigned long long */ void prikazi_ull(unsigned long long x){ unsigned long long maska = 1ULL << 63; /* Obratiti paznju na sufiks ULL iza konstante 1. Celobrojne konstante su podrazumevano tipa int. Ovo ih ogranicava na 32 bita. Da bismo radili sa 64bitnim konstantama, koristimo sufiks ULL da bismo naglasili da zelimo da bude tipa unsigned long long */ while(maska){ putchar(x & maska ? '1' : '0'); maska >>= 1; } } /* Funkcija prikazuje bitove double podatka. */ void prikazi_double_2(double x){ LFLD lfld; lfld.lf = x; prikazi_ull(lfld.d); } /* Ista stvar pomocu konverzije pokazivaca */ void prikazi_double_3(double x){ prikazi_ull(*(unsigned long long *)&x); } /* Funkcija prikazuje bitove karakterskog tipa x */ void prikazi_char(unsigned char x){ unsigned maska = 1 << 7; while(maska){ putchar(x & maska ? '1' : '0'); maska >>= 1; } } /* Funkcija prikazuje binarni zapis proizvoljnog podatka na adresi x velicine size bajtova */ void prikazi_podatak(void * x, int n){ char * p = (char *) x; /* void pokazivac se konvertuje u char pokazivac */ int i; /* Sada se memorijski sadrzaj velicine n bajtova tumaci kao niz karaktera duzine size. Bitovi tih bajtova se redom prikazuju na izlazu */ for(i = n - 1; i >= 0; i--) prikazi_char(p[i]); /* NAPOMENA: Bajtovi se u prethodnoj petlji prikazuju u obrnutom poretku, zato sto IA-32 arhitektura spada u tzv. "Little Endian" arhitekture. Kod ovih arhitektura se visebajtni podaci u memoriji rasporedjuju tako de su bajtovi manje tezine na manjim adresama. Nasuprot ovih, postoje i tzv. "Big Endian" arhitekture, kod kojih se nizi bajtovi visebajtnih podataka smestaju na visim adresama u memoriji. */ } /* Test program */ int main(){ // double y = 123.321; float y = 12.35f; prikazi_podatak(&y, sizeof(y)); putchar('\n'); return 0; }