přístup na byty v int C

Josef Štengl ok1ced na nagano.cz
Úterý Říjen 29 08:34:38 CET 2013


Souhlasím, jen doplním.

Pokud převádíte číslo z jedné velikosti typu do jiné a to oběma směry včetně prohazování bytů (pro ten samý typ) zapomeňte 
na na ukazatele a použijte bitové posuny:
  · ukazatele jsou závislé na endianitě (litte endian je sice dominantní leč ne jediný používaný)
  · přistupování ke stejné oblasti paměti pomocí ukazatelů na rozdílné velikosti je poněkud ošemetná věc, a je od C99 
poněkud zpřísněna (viz  strict aliasing rule), see níže.
  · kompilátory většinou tyto konstrukce rozpoznávají a překládají optimalizovaně. Je pak docela deprimující, že se píšete 
se čtyřmi delšími řádkami a vypadne z toho jedna instrukce :-)

Na union také pozapomeňte, protože u něj není zaručeno nic, kromě vnějšího chování (viz norma). Když už je vhodné ho 
nasadit, tak se nasazuje se znalostí implementace daného kompilátoru. Další možný problém je při přístupu k proměnným 
zarovnaným na hranici typu, ale to jsem nikdy neměl potřebu ověřovat.

A máte to vyřešeno :-).

Na ukazatele to chce vhodnější příklad.

ced




==================================================================

Zpřísněná pravidla pro přistupování k datům různými typy (pro C99 z C90)

– more precise aliasing rules via effective type

Info: Tuto problematiku lze vyhledat pod heslem strict aliasing rule.

Strict aliasing7) znamená, že kompilátor předpokládá, že dva objekty různého typu neodkazují na stejnou oblast paměti. Při 
nedodržení tohoto pravidla mohou po překladu vzniknout obtížně odhalitelné chyby8).

Důvodem zavedení tohoto pravidla je aby autoři kompilátoru mohly bezpečně předpokládat, že změna jedné proměnné se 
neprojeví změnou jiné. A naopak, kdy mají předpokládat, že proměnné mohou ukazovat na stejnou oblast paměti.

Například:

typedef struct
{
         uint16_t a;
         uint32_t b;
} sa_t;

typedef struct
{
         uint16_t a;
         uint32_t b;
} sb_t;

sa_t *a;
sb_t *b;

V tomto případě kompilátor předpokládá, že *a a *b neodkazují na stejnou oblast paměti ačkoliv formát struktur je shodný.

sa_t *c, *d;

int16_t i;
int16_t *p = &i;

Kompilátor předpokládá, že *c a *d resp i a *p mohou respektive odkazují na stejnou oblast paměti a nebude používat 
příslušné optimalizace.

Nebo.

int16_t i;
void fce(int16_t *j, int16_t *k);

fce(&i, &i);

Pokud je funkce fce() volána tímto stylem (stejné typy parametrů, resp hodnota parametru), tak se předpokládá, žej a k 
ukazují na stejnou oblast paměti.

Převedení a dereference neshodných ukazatelů obvykle znamená porušení tohoto pravidla. Striktní aliasing je předpokládán C 
kompilátorem, kterýžto předpokládá, že dereference ukazatelů na objekty rozdílného typu nebudou odkazovat na shodnou 
oblast paměti9)

Pravidla pro aliasing určují okolnosti za kterých objekt může mít alias10) jsou definovány v kapitole 6.5 bod 7 standardu C99.
Možné vytváření aliasů

Vytváření aliasů je možné jen pro objekt k němuž je přistupováno pouze výrazem odkazujícím do oblasti paměti (lvalue) v 
těchto případech.

     Efektivní typ nebo kvalifikovaná verze typu je shodná nebo kompatibilní s efektivním typem objektu.

Prakticky to znamená, že typy jsou kompatibilní pokud nejsou rozdílné datové typy, modifikátory mohou být různé.

uint32_t var;
uint32_t* const       a = &var;
uint32_t* volatile    b = &var;


     Typ celých nebo přirozených čísel kompatibilní s typem (efektivní nebo s kvalifikovanou verzí) objektu.

int32_t*              c = (int32_t*)&var;
int32_t* const        d = (int32_t*)&var;
int32_t* volatile     e = (int32_t*)&var;
const int32_t* const  f = (int32_t*)&var;


     Jednotlivé členy agregovaného typu (stuct) a typu union splňující předchozí podmínky (včetně vnořených členů).

struct s
{
         int32_t j;
         int32_t i;
         union u
         {
                 uint32_t u;
                 double d;
         }
};

double *f = &s.u.d;


     typ char Datové typy char*, signed char*, nebo unsigned char* mohou ukazovat kamkoliv na platnou adresu paměti bez 
omezení.

uint64_t long;
int8_t* malej = (int8_t *)&long;




Dne 29.10.2013 01:17, Radek Benedikt napsal(a):
> Miroslav Draxal píše v Po 28. 10. 2013 v 23:10 +0100:
>> Samozřejmě, tudy cesta vede. Mě vrtá spíš jak to udělat přes ukazatele.
>> Určitě to nějak jde. Abych se něco naučil. Míra
>
>>> Ještě jsem zapomněl přidat jak to dělám do teď. Ale moc se mi to
>>> nelíbí.**
>>> **
>>>
>>>                                Linear.Krok = eeprom_read
>>> (EEpromLinearKorekce);****
>>>
>>>                                Linear.Krok <<= 8;****
>>>
>>>                                Linear.Krok |= eeprom_read
>>> (EEpromLinearKorekce+1);****
>>>
>>> ** **
>>>
>>> Jak přistoupit přes ukazatele na int Linear.krok (byt1 ; byt2)?****
>
> 	Slo by pretypovat pointer na Linear.krok na typ pointer na byte,
> protoze inkrement ukazatele je o delku typu, nikoliv o byte. Nicmene je
> to trochu drbani levou rukou za pravym uchem.
> 	Ukazatele bych nechal na pokoji a napsal bych to nacteni na jeden
> radek, misto na tri.Usnadni se tim kompilatoru prace s optimalizaci.
> Tohle je zrovna dost bezna konstrukce a kompilatory ji obvykle umi.
> Nesmi v ni byt ale neco co zavisi na poradi cteni te korekce z EEprom.
> Pak se ale neda spolehnout ani na to rozepsani na tri
> radky.Optimalizatory pri agresivnim nastaveni umi sahnout i do takoveto
> konstrukce. Optimalizace pointrove aritmetiky v prekladaci uz obvykle
> tak slusna neni, je to spis o rucni optimalizaci. Jenze pri ni se do
> toho zacinaji michat strojove zavisle veci a je pak sranda ten zdrojak
> portovat jinam. Objevi se napr. problem little/big endian.
> 	Navic na vyse popsane konstrukci je videt, ze v podstate prirazeni int
> do int muze byt zpracovavane na nekolik kroku a neni proto atomicke. Je
> to docela sranda pri preruseni, kdyz by se cela ta korekce jednou za cas
> doladovala a skocila napr. z  0x3FF na 0x400. To ale jen na okraj.
>
> 	Radek (bendikt2hw.cz)
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list
>


Další informace o konferenci Hw-list