/* Celobrojni tipovi podataka */

/* Pogledati na primer: http://home.att.net/~jackklein/c/inttypes.html */

// C99 kod - npr. deklaracije nisu iskljucivo na pocetku bloka, komentari //, koristi se long long 

#include <stdio.h>
#include <limits.h>

int main() {
  /*
    Osnovni tipovi su odredjeni duzinom i nacinom zapisa:
    ---------------------------------------------------------------
                    | oznaceni (signed)    | neoznaceni (unsigned)
    ---------------------------------------------------------------
    karakteri       | signed char          | unsigned char
    (char)          |                      |
    ---------------------------------------------------------------
    kratki          | signed short int     | unsigned short int
    (short int)     |                      |
    ---------------------------------------------------------------
    dugacki         | signed long int      | unsigned long int
    (long int)      |                      |
    ---------------------------------------------------------------
    veoma dugacki   | signed long long int | unsigned long long int
    (long long int) |                      |
    - samo C99 -    |                      |
    ---------------------------------------------------------------


    Uobicajeni zapisi (vazi i na x86 + gcc platformi na kojoj radimo):
    ------------------------------------------------------------------
                    | oznaceni (signed)        | neoznaceni (unsigned)
    ------------------------------------------------------------------
    karakteri       | 1B = 8b                  | 1B = 8b
                    | [-2^7, 2^7-1] =          | [0, 2^8-1] = 
    (char)          | [-128, 127]              | [0, 255]
    ------------------------------------------------------------------
    kratki          | 2B = 16b                 | 2B = 16b
    (short int)     | [-32K, 32K-1] =          | [0, 64K-1] = 
                    | [-2^15, 2^15-1] =        | [0, 2^16-1] = 
                    | [-32768, 32767]          | [0, 65535]
    ------------------------------------------------------------------
    dugacki         | 4B = 32b                 | 4B = 32b
    (long int)      | [-2G, 2G-1] =            | [0, 4G-1] = 
                    | [-2^31, 2^31-1] =        | [0, 2^32-1] = 
                    | [-2147483648,2147483647] | [0, 4294967295]
    ------------------------------------------------------------------
    veoma dugacki   | 8B = 64b                 | 8B = 64b
    (long long int) | [-2^63, 2^63-1] =        | [0, 2^64-1] = 
                    | [-9.2*10^18, 9.2*10^18]  | [0, 1.84*10^19]
    ------------------------------------------------------------------

    Moguci su i izvedeni (skraceni) tipovi:

    char                 - podudara se sa signed char ili sa unsigned char - 
    nedefinisano standardom
                
    int se moze izostaviti:
    short                - isto sto i short int
    signed short         - isto sto i signed short int
    unsigned short       - isto sto i unsigned short int
    long                 - isto sto i long int
    signed long          - isto sto i signed long int
    unsigned long        - isto sto i unsigned long int
    long long            - isto sto i long long int
    signed long long     - isto sto i singed long long int
    unsigned long long   - isto sto i unsinged long long int
    signed               - isto sto i signed int
    unsinged             - isto sto i unsigned int

    signed/unsigned se moze izostaviti za int i tada se podrazumeva signed:
    int                  - isto sto i signed int
    short int            - isto sto i signed short int
    long int             - isto sto i signed long int
    long long int        - isto sto i signed long long int
 
    short/long/long long se moze izostaviti i tada se podrazumeva nativna duzina
    za masinu (obicno long):
    signed int           - obicno se podudara sa signed long int
    unsigned int         - obicno se podudara sa unsigned long int

    Iako se char cesto podudara sa signed char, to su razliciti tipovi podataka.
    Slicno vazi i za tipove int i long int.
  */

  /* Formati za funkciju printf koji se koriste u nastavku koda: 
     %d - dekadni oznaceni broj, %u - dekadni neoznaceni broj,  
     %x - heksadekadni neoznaceni broj, %c - karakter
     %l - dugacki, %ll veoma dugacki
  */
  
  /* Rasponi su definisani simbolickim konstantama u <limits.h> (???_MIN, ???_MAX) */

  signed char sc_min = SCHAR_MIN;
  signed char sc_max = SCHAR_MAX;
  printf("signed char: [%d, %d]\n", sc_min, sc_max);
  unsigned char uc_min = 0;
  unsigned char uc_max = UCHAR_MAX;
  printf("unsigned char: [%d, %d]\n", uc_min, uc_max);
  char c_min = CHAR_MIN;
  char c_max = CHAR_MAX;
  printf("char: [%d, %d]\n", c_min, c_max);
  printf("Number of bits in a character: %d\n", CHAR_BIT);
  printf("Size of character is %d byte\n", sizeof(char));

  int i_min = INT_MIN;
  int i_max = INT_MAX;
  printf("int: [%d, %d]\n", i_min, i_max);
  printf("Size of int is %d bytes\n", sizeof(int));

  signed short int ssi_min = SHRT_MIN;
  signed short int ssi_max = SHRT_MAX;
  printf("signed short int: [%d, %d]\n", ssi_min, ssi_max);
  unsigned short int usi_min = 0;
  unsigned short int usi_max = USHRT_MAX;
  printf("unsigned short int: [%u, %u]\n", usi_min, usi_max);
  printf("Size of short is %d bytes\n", sizeof(short));

  signed long int sli_min = LONG_MIN;
  signed long int sli_max = LONG_MAX;
  printf("signed long int: [%ld, %ld]\n", sli_min, sli_max);
  unsigned long int uli_min = 0;
  unsigned long int uli_max = ULONG_MAX;
  printf("unsigned long int: [%lu, %lu]\n", uli_min, uli_max);
  printf("Size of long is %d bytes\n", sizeof(long));

  signed long long int slli_min = LLONG_MIN;
  signed long long int slli_max = LLONG_MAX;
  printf("signed long long int: [%lld, %lld]\n", slli_min, slli_max);
  unsigned long long int ulli_min = 0;
  unsigned long long int ulli_max = ULLONG_MAX;
  printf("unsigned long long int: [%llu, %llu]\n", ulli_min, ulli_max);
  printf("Size of long long is %d bytes\n", sizeof(long long));

  
  /* Oznaceni brojevi. Obicno se koristi samo int. */
  int i1 = 10;          /* Dekadni celobrojni literal */
  printf("int i1 = 10; --> i1 = %d\n", i1);
  int i2 = 010;         /* Oktalni celobrojni literal */
  printf("int i2 = 010; --> i2 = %d\n", i2);
  int i3 = 0x10;        /* Heksadekadni celobrojni literal */
  printf("int i3 = 0x10; --> i3 = %d\n", i3);
  int i4 = -234;        /* Negativna vrednost */
  printf("int i4 = -234; %%d --> i4 = %d\n", i4);
  printf("int i4 = -234; %%u --> i4 = %u\n", i4);   /* Pogresno navedeno %u umesto %d */
  int i5 = INT_MAX + 1; /* Vece od najvece moguce vrednosti - prekoracenje */
  printf("int i5 = INT_MAX + 1; --> i5 = %d\n", i5);
  int i6 = 14+5*7;      /* Promenljiva se moze inicijalizovati i
                           konstantnim izrazom */
  printf("int i6 = 14+5*7; --> i6 = %d\n", i6);

  /* Neoznaceni brojevi. Obicno se koristi samo unsigned. */
  unsigned u1 = 10u;         /* Dekadni neoznaceni celobrojni literal */
  printf("unsigned u1 = 10u; --> u1 = %u\n", u1);
  unsigned u2 = 10U;         /* u ili U, svejedno je.*/
  printf("unsigned u2 = 10U; --> u2 = %u\n", u2);
  unsigned u3 = 10;         /* nekad moze i da se ne navede */
  printf("unsigned u3 = 10; --> u3 = %u\n", u3);
  unsigned u4 = 0xffffffffu; /* Heksadekadni neoznaceni celobrojni literal */
  printf("unsigned u4 = 0xffffffffu; %%u --> u3 = %u\n", u4);
  printf("unsigned u4 = 0xffffffffu; %%x --> u3 = %x\n", u4);
  printf("unsigned u4 = 0xffffffffu; %%d --> u3 = %d\n", u4);
  unsigned long u4 = 123456789ul; /* l (ili L) oznacava eksplicitno da
                                     je u pitanju dugacki broj*/
  printf("unsigned long u4 = 123456789ul; --> u4 = %lu\n", u4);

  /* Neoznaceni kratki brojevi - primeri prekoracenja i konverzija */
  unsigned short us1 = 1234u;    /* U redu */
  unsigned short us2 = 123456u;  /* Preveliki literal - ne moze da se smesti u unsigned short */
  unsigned short us3 = -1;      /* Negativan literal - ne moze da se smesti u unsigned short */
  unsigned short us4 = u1;      /* U redu - konverzija bez gubitka */
  unsigned short us5 = u3;      /* Konverzija sa gubitkom informacije */

  printf("unsigned short us1 = 1234; --> us1 = %u\n", us1);
  printf("unsigned short us2 = 123456; --> us2 = %u\n", us2);
  printf("unsigned short us3 = -1; --> us3 = %u\n", us3);
  printf("unsigned short us4 = u1; --> us4 = %u\n", us4);
  printf("unsigned short us5 = u3; --> us5 = %u\n", us5);

  /* Karakteri - prikaz sa %d i %c */
  char c1 = 65;
  printf("char c1 = 65; %%d --> c1 = %d\n", c1);
  printf("char c1 = 65; %%c --> c1 = %c\n", c1);

  char c2 = 'A';
  printf("char c2 = 'A'; %%d --> c1 = %d\n", c2);
  printf("char c2 = 'A'; %%c --> c1 = %c\n", c2);

  char c3 = '\x41';
  printf("char c3 = '\\x41'; %%d --> c1 = %d\n", c3);
  printf("char c3 = '\\x41'; %%c --> c1 = %c\n", c3);

  // Nema nikakve razlike izmedju c1, c2 i c3

  /* Specijalne sekvence: \n, \\, \t, ... */
  char c4 = '\n';
  printf("char c4 = '\\n'; %%d --> c4 = %d\n", c4);
  printf("char c4 = '\\n'; %%c --> c4 = %c\n", c4);

  char c5 = '\\';
  printf("char c5 = '\\\\'; %%d --> c4 = %d\n", c5);
  printf("char c5 = '\\\\'; %%c --> c4 = %c\n", c5);

  return 0;
}