..
byte sbs( "Hello World" );
5.2.1.4. Łańcuchy HLA
Póki nie przeszkadza nam kilka dodatkowych bajtów narzutu, można stworzyć format łańcuchów łączących w sobie zalety łańcuchów poprzedzonych długością i zakończonych zerem, unikając jednocześnie wad jednych i drugich. Przykładem jest natywny format łańcuchów języka HLA7.
Najpoważniejszą wadą łańcuchów w formacie HLA jest duży narzut na każdy łańcuch.
Procentowo może on być szczególnie istotny w środowiskach o ograniczonych zaso-bach i w przypadku korzystania z wielu krótkich łańcuchów. Łańcuchy HLA zawierają zarówno długość przed łańcuchem właściwym, jak i kończący bajt zerowy, a także inne informacje; łącznie narzut wynosi dziewięć bajtów na łańcuch8.
7 Zwróćmy uwagę na to, że HLA jest asemblerem, więc można — i to bez trudu — obsłużyć w nim praktycznie dowolny rozsądny format łańcuchów. Natywny format łańcuchów HLA wykorzystywany jest w stałych literałach; jest on też używany przez większość procedur z biblioteki standardowej HLA.
8 Tak naprawdę, w związku z wymaganiami co do wyrównania danych w pamięci, narzut dla niektórych łańcuchów może sięgać 12 bajtów.
Rozdział 5. ♦ Dane znakowe
111
Format HLA wykorzystuje 4-bajtowy przedrostek opisujący długość; dzięki temu długość ta może być nieco większa niż cztery miliardy znaków (jest to oczywiście o wiele więcej, niż w ogóle znajduje praktyczne zastosowanie). HLA wstawia też na koniec danych łańcuchowych bajt zerowy, dzięki czemu łańcuchy HLA są zgodne funkcjami obsługującymi łańcuchy zakończone zerem (pod warunkiem, że funkcje te nie zmieniają długości łańcuchów). Następne cztery dodatkowe bajty w łańcuchu HLA zawierają maksymalną dopuszczalną długość łańcucha. Dzięki temu dodatkowemu polu funkcje obsługujące w HLA łańcuchy mogą w razie potrzeby sprawdzić, czy nie wystąpiło przepełnienie. Na rysunku 5.2 pokazano postać łańcucha HLA w pamięci.
Rysunek 5.2.
Format łańcuchów
HLA
Cztery bajty znajdujące się tuż przed pierwszym znakiem łańcucha to faktyczna jego długość. Cztery poprzednie bajty to maksymalna długość łańcucha. Za znakami wchodzącymi w skład tekstu znajduje się bajt zerowy. HLA gwarantuje, że cała struktura danych łańcucha będzie wielokrotnością czterech bajtów (jest to korzystne z uwagi na wydajność), więc na końcu takiego obiektu może znajdować się do trzech bajtów wy-pełnienia (aby struktura z rysunku 5.2 miała długość będącą wielokrotnością czterech bajtów, wystarczą dwa bajty wypełnienia).
Zmienne łańcuchowe HLA to wskaźniki zawierające adres bajta z pierwszym znakiem łańcucha. Aby sięgnąć do pól określających długość, trzeba załadować wartość wskaźnika do rejestru 32-bitowego. Do pola określającego długość sięgamy, podając offset równy
–4, a do pola określającego długość maksymalną — offset równy –8. Oto przykład: static
s :string := "Hello World";
...
mov( s, esi ); // Do esi wstawiamy adres litery 'H'
// z napisu "Hello World"
mov( [esi-4], ecx ); // Długość łańcucha wstawiamy do ECX (dla "Hello
// World" jest to 11).
...
mov( s, esi );
cmp( eax, [esi-8] ); // Sprawdzamy, czy długość z EAX przekracza
// maksymalną długość łańcucha.
ja StringOverflow;
Miłą cechą zmiennych łańcuchowych HLA jest to, że (jako obiekty tylko do odczytu) są one kompatybilne z łańcuchami zakończonymi zerem. Na przykład, jeśli mamy funkcję języka C (lub innego) spodziewającą się jako parametru łańcucha zakończonego zerem, możemy wywołać ją, przekazując jej łańcuch HLA:
jakasFunkcjaC( zmiennaLancuchowaHLA );
Jedynym problemem jest to, że funkcja ta nie może w żaden sposób zmieniać długo-
ści łańcucha (gdyż kod C nie skorygowałby pola określającego długość). Oczywiście, przy powrocie zawsze można byłoby użyć funkcji C strlen, aby sprawdzić długość łańcucha i w razie potrzeby ją skorygować, ale modyfikowanie długości łańcuchów HLA z zewnątrz w zasadzie jest kiepskim pomysłem.
112
Profesjonalne programowanie. Część 1. Zrozumieć komputer
5.2.1.5. Łańcuchy z deskryptorem