Jste zde

Méně známé skutečnosti o C a C++: Ukazatel není číslo

Pravidelně se setkávám s mylným názorem, že "ukazatel je číslo". V tomto příspěvku bych chtěl (1) poukázat na to, že tvrdit, že "ukazatel je číslo", je to stejné, jako tvrdit, že "Bozetechova 2, 612 66 Brno, Czech Republic" je číslo a (2) že ukazatele a čísla nelze jen tak mezi sebou převádět.

Co to teda ukazatel je?

Ukazatel je datový typ sloužící k uložení adresy nějakého objektu (např. v paměti). Jak taková adresa vypadá, závisí na architektuře. V případě paměti se může jednat např. o tzv. plochý paměťový model, kde programátor vidí paměťový prostor jako jednoduché pole, segmentovaný model, kde adresa místa v paměti je složena za dvou částí (segment a offset), či libovolný jiný model. Když uvidíte něco jako 3445:6673, tak těžko řeknete, že to je číslo, protože číslice ":" normálně neexistuje (pokud si nezavedete nějakou vaši speciální číselnou soustavu). Může to být ale adresa, která je právě složena ze segmentu a offsetu. A ano, můžete se na tato dvě čísla podívat jako na jedno číslo, když je spojíte dohromady. To už se ale nedíváte na adresu jako takovou, ale na její reprezentaci. Hardwareář by řekl: "na nejnižší úrovni je ukazatel vlastně vždy reprezentován jako číslo".

Zkusím dát jiný příklad. Když si např. vezmete adresu Bozetechova 2, 612 66 Brno, Czech Republic, tak pochybuji, že o ní řeknete, že to je číslo. Jasně, můžete tuto adresu reprezentovat jako číslo vhodným kódováním (např. ASCII). Co tím teda chce blogger říct? Že je třeba si uvědomit následující:

Ukazatel je adresa, která může být (a bývá) reprezentována jako číslo.

Pokud byste chtěli být ještě přesnější, tak do toho zakomponujte i to, že se jedná o datový typ. Ale pro názornost to, myslím, stačí.

OK, a jak je to s tím převodem ukazatele na int?

Na začátek něco z normy C99 (sekce 6.3.2.3; u C++98 je to obdobné). Libovolný ukazatel lze převést (konverze) na int a naopak. S výjimkou nulového ukazatele je ovšem výsledek implementačně závislý. Co to znamená? Že takovéto kejkle jsou naprosto nepřenositelné. Hodně lidí žije v představě, že sizeof(int *) == sizeof(int). Někdy tomu tak být může, ale není to rozhodně pravidlem. Pokud sizeof(int *) > sizeof(int), tak vám je jasné, že ne každou adresa lze uložit do proměnné typu int, a tak přijdete o část informace a dostanete nesmysl (např. při pokusu o zpětnou konverzi na ukazatel)... Takže prosím, ve svém zájmu, nedělejte to!

Jaké problémy tím mohou vzniknout, tak na to se podívejte např. zde.

No jó, ale já bych to fakt moc moc moc chtěl!

Krátká poznámka na konec. Následující řádky se vztahují na C99, v C++ by tato podpora měla být od C++0X. Od C99 je ve standardní knihovně hlavičkový soubor stdint.h, který, mimo jiné, obsahuje dva integrální typy, které lze bezpečně použít pro konverzi ukazatele na číslo a naopak (viz sekce 7.18.1.4. v normě). Takže se, v případě zájmu, podívejte na datové typy intptr_t a uintptr_t.

Přidat komentář