CURSUL 6

Referirea prin pointeri la structuri

CÂMPURI DE BITI
 

Un membru de tip întreg al unei structuri poate fi declarat ca fiind reprezentat în memorie pe un numãr specificat de biti, cuprins între 1 si numãrul maxim de biti pe care este memoratã o variabilã de acel tip. Un astfel de membru se numeste câmp de biti.

Exemplul 1. În cazul unui joc de cãrti, o carte de joc poate fi reprezentatã printr-o structurã:

struct Carte {
    unsigned char valoare; //un numãr cuprins între 1 si 14
    unsigned char culoare; //un numãr cuprins între 0 si 3
};
Pentru culoare se pot utiliza constantele simbolice
#define CARO 0
#define CUPA 1
#define PICA 2
#define TREFLA 3
Pachetul de cãrti fiind reprezentat de vectorul:

struct Carte pachet[52];

Dacã sizeof(unsigned char) este 1, atunci sizeof ( pachet ) va da ca rezultat 104. Însã este evident cã nu aven nevoie de 8 biti , cât are unsigned char, pentru a reprezenta valoarea sau culoarea unei cãrti. Pentru valoare sunt suficienti 4 biti, iar pentru culoare 2. De aceea se va da o nouã definitie a structurii Carte, utilizând câmpuri de biti:

struct carte {
    unsigned valoare : 4; // 4 biti -> [0,15]
    unsigned culoare : 2; // 2 biti -> [0, 3]
};
struct carte Pachet[52];
 
Obsevatie. Câmpurile de biti trebuie sã aibã tipul int sau unsigned. Dacã s-ar fi declarat

unsigned char valoare : 4;
atunci compilatorul ar fi emis un avertisment. Sintaxa câmpurilor de biti este urmãtoarea:

<camp_de_biti> ::= <tip_int> [<ident>] <expresie_const_int>
<tip_int> ::= int | unsigned
 
Cu câmpurile de biti se pot efectua aceleasi operatii si sunt referite în acelasi mod ca si oricare membru al structurilor. Sã considerãm urmãtorul program.
 
#define CARO 0
#define CUPA 1
#define PICA 2
#define TREFLA 3
void main()
{
    struct carte Pachet[52];
    int nr_oct=sizeof(Pachet);
 
    Pachet[1].valoare=7;
    Pachet[1].culoare=CUPA;
    printf("\nLung. pachet=%d octeti. Cartea este (%d,%d)",
                nr_oct, Pachet[1].valoare, Pachet[1].culoare );
}
Iesirea produsã de program:
 
Lung. pachet=52 octeti. Cartea este (7,1)
 

Reprezentarea fizicã a câmpurilor de biti (aliniere, posibilitatea ca un câmp sã se întindã pe mai multe unitãti de alocare) este dependentã de masinã. Bitii neutilizati ai unei variabile structurate nu pot fi folositi de altã variabilã structuratã. Într-un câmp de biti reprezentat pe int, bitul cel mai semnificativ este este considerat, de regulã, bit de semn.
 

Exemplul 2. Rezultatul produs de programul de mai jos depinde de "masinã".
 
#include <stdio.h>
void main()
{
    struct ExUnBit {
        int bits_1 :1, bits_3 :3;
        unsigned bitu_1:1, bitu_3:3;
    } o;

o.bits_1 = o.bitu_1 = 1; //se memoreaza bitii '1' si '1'
o.bits_3 = o.bitu_3 = 7; //se memoreaza bitii '111' si '111'

printf ("%d %d %d %d", o.bits_1, o.bitu_1, o.bits_3, o.bitu_3);

}
Rezultat:
-1 1 -1 7
 
Se observã din sintaxã cã <ident> poate lipsi (se reaminteste cã [ ] reprezintã optional ). Dacã lipseste, rolul acelui câmp este doar de a rezerva un anumit numãr de biti. Dacã expresia întreagã constantã <expresie_const_int> ce urmeazã dupã ':' în declaratia unei structuri are valoarea 0, atunci membrul urmãtor al structurii va fi memorat în urmãtoarea unitate de alocare a memoriei (octet, cuvânt de 2 octeti etc.).

Exemplul 3.

struct student {
    char nume[20];
    unsigned an_nastere:11 ; // [0,2048]
    unsigned sex:1 ;
    unsigned :2; // se lasa liberi 2 biti
    unsigned notaex1:4, calific1:1;
    unsigned :0; // urmatorul membru va incepe
                // la o noua unitate de alocare a memoriei
    unsigned notaex2:4; //4 este nr. de biti
} x;
 

Se va observa cã variabila structuratã x este reprezentatã pe 24 octeti, dar dacã se va elimina câmpul de biti unsigned :0; atunci x va ocupa doar 23 de octeti. În loc de unsigned :0; se putea utiliza unsigned :6; cu acelasi efect.
Utilitatea câmpurilor de biti constã în economia de memorie
 

UNIUNI

O uniune reprezintã tot un tip structurat, însã, spre deosebire de structuri, membrii unei uniuni utilizeazã în comun aceeasi zonã de memorie.
 
Exemplul 4.
// Programul union.c
// PSG/30/03/2000
#include <stdio.h>
#define Print printf("\nx.i=%d x.r=%e", x.i, x.r)
void main()
{
    union numar {
        int i;
        float r;
    };

    typedef union numar NUMAR;
    NUMAR x;
 
    x.i=1980;
    Print;
    x.r=1980.0;
    Print;
}
x.i=1980 x.r=8.431804e-16 
x.i=-32768 x.r=1.980000e+03
 

Important. La un moment dat numai o singurã valoare este retinutã în variabila union.

Uniunile sunt utilizate tot pentru a face economie de memorie în cazul unor variabile care pot avea multiple interpretãri. Rãmâne în sarcina programatorului sã asigure o gestiune corectã a membrilor unei uniuni.

Exemplul 5.
// Programul union2.c Un exemplu de struct cu union
// PSG/30/03/2000
#include <stdio.h>
#define CHAR 0
#define INT 1
#define FLOAT 2
#define DOUBLE 3
#define POINTER 4
#define Print(x) printf(format[a.tip], x);
 
typedef union {
    char c;
    int i;
    float r;
    double d;
    void *p;
} valoare;

typedef struct {
    char tip;     // indica tipul membrului val, care
    valoare val; // este o uniune
} VARIABILA;
 
void Afisare (VARIABILA);
void main()
{
    VARIABILA x;
    printf("\nO valoare intreaga: ");
    x.tip=INT; x.val.i=1980;
    Afisare (x);
    printf("\nUn pointer: ");
    x.tip=POINTER; x.val.p=&x;
    Afisare (x);
}
void Afisare (VARIABILA a)
{
    static char *format[]={ "%c", "%d", "%f", "%lf", "%p"};
    switch (a.tip) {
        case CHAR: Print (a.val.c);
                    break;
        case INT: Print (a.val.i);
                    break;
        case FLOAT: Print (a.val.r);
                    break;
        case DOUBLE: Print (a.val.d);
                    break;
        case POINTER: Print (a.val.p);
                    break;
        default: printf("Err.Tip incorect");
                    break; //preventiv
    }
}
Rezultat:
O valoare intreaga: 1980
Un pointer: 392C:0FF6

Se va observa faptul cã sizeof(x) este egal cu sizeof(char)+sizeof(val), iar sizeof(val) este egal cu sizeof(double), deoarece toti membrii unei uniuni partajeazã aceeasi zonã de memorie, având dimensiunea egalã cu dimensiunea maximã a membrilor sãi.



Exercitiu. Care este afissarea produsã de programul de mai jos ?
#include <stdio.h>
typedef struct {unsigned b0:1, b1:1, b2:1, b3:1,
b4:1, b5:1, b6:1, b7:1;} OCTET;
typedef struct {
    OCTET low;
    OCTET high;
} CUVANT;

typedef struct {
    char octetl, octeth;
} OCTETI;

union Cuvant {
    char c;
    OCTET bit;
    CUVANT oct;
    OCTETI zona;
    unsigned u;
} cuv={0};

void PrintBiti ( OCTET );

void main()
{
    cuv.c = 'A';
    cuv.oct.high.b0=1;
    printf("\nCar=%c cuv=%x bitul" "6=%d\n", cuv.zona.octetl, cuv.u,
    cuv.bit.b6);
    PrintBiti (cuv.oct.high);
    PrintBiti (cuv.oct.low);
}

void PrintBiti ( OCTET o)
{
    printf("%d%d%d%d." , o.b7, o.b6, o.b5, o.b4);
    printf("%d%d%d%d ", o.b3, o.b2, o.b1, o.b0);
}



Rezultat. Pe un rând: Car=A cuv=141 bitul 6=1 si pe urmãtorul: 0000.0001 0100.0001

[Pagina universitatii]  [Pagina facultatii]  [Catalog biblioteca]  [Pagina prof. St.Gh.Pentiuc]