Rzutowanie

Adam Boduch

Rzutowanie to sposób na ?oszukanie? kompilatora. Jeżeli nie jesteśmy pewni, co robimy, możemy w konsekwencji doprowadzić do wystąpienia poważnych błędów podczas działania programu.

Najlepiej omówić to na przykładzie. Oto prosty kod źródłowy, który na pewno nie zostanie prawidłowo skompilowany:

var C: Char;
    B: Byte;
begin
  C := 'A';
  B := C;
end.

Dane w postaci Char (pojedynczy znak) próbujemy tu przypisać do zmiennej VarB, która jest zmienną typu Byte. Oczywiście kompilator wskaże błąd: [Error] typcast.dpr(12): Incompatible types: 'Byte' and 'Char'. Po drobnej modyfikacji cały program zostanie skompilowany prawidłowo i zadziała bez problemu:

var C: Char;
    B: Byte;
begin
  C := 'A';
  B := Byte(C); //  rzutowanie
end.

Rzutowaniem jest właśnie przypisanie danych w ten sposób: Byte(C). W takim przypadku rzutujemy typ Char na Byte, w wyniku czego zmienna B będzie posiadać wartość 65 (kod ASCII litery A).

Funkcja Messagebox wymaga typu PChar (który również jest typem znakowym), zatem należy zastosować następujące rzutowanie:

MessageBox(0, PChar(IntToStr(Zmienna_Integer)), 'Tytuł programu', MB_ICONINFORMATION);

5 komentarzy

Jestem nowy (user) ale raczej kumam o co chodzi.
Mianowicie:

W rzutowaniu zawsze zachodzi odwołanie do adresu pamięci w której przechowywana jest zmienna.

  1. w pierwszym rzutowaniu następuje odwołanie do adresu zmiennej typu integer (integer to 32 bity = 4 bajty). Na jej danych chcemy utworzyć zmienną typu string. Problem jest jeden ... string to ciąg znaków (może być pusty) zawsze zakończony dwoma bajtami o wartości zero. Tak więc rzutowanie (i tym samym wymuszanie) aby z wartości nie zakończonej zerem zrobił się string nie ma zbyt dużych szans. Problemem staje się to, że programy mogą odwoływać się tylko do przedziału pamięci zadeklarowanej w programie - jakiekolwiek odwołanie się poza ten przedział zawsze wywoła naruszenie bezbieczeństwa systemu (lub czegoś w tym stylu).

  2. w drugim rzutowowaniu znowu następuje odczyt danych spod adresu zmiennej - tej z której rzutujemy. W tym przypadku następuje przekształcenie z pamięci XX XX XX 00 00 (czyli: znak, znak, znak, 00, 00 - string '111' zajmuje 5 bajtów). Ciąg '111' powinien dokładnie wyglądać (szesnastkowo) tak: 31 31 31 00 00. Zmienna typu string (tak jak i każda inna zmienna) to wskaźnik do adresu pamięci - string wskazuje na pierwszy bajt pamięci (pierwszy znak ciągu). Zmienna typu integer jak już mówiłem to 4 bajty a więc odczytuje ona tylko pierwsze cztery (z pięciu) ze zmiennej string. Jednym słowem w tym przypadku konwersja (rzutowanie) to pikuś - Pan Pikuś.

Przy rzutowaniu trzeba znać się na typach pamięci - wszystko jest w helpie ... jeżeli chodzi o typy zmiennych. Trzeba zapamiętać jedno - nie wszystko da się zrzutować!

PS. W opisie odwołuję się do "FALCO dnia 19-04-2006 19:01 ".

program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils;
var
a: ShortString = 'A';
s: integer;
begin
//: Zmienna a w pamięci w zapisie HEX wygląda tak:
//: 41000000000000....00
//: Jest to 41 i 254x00
//: I teraz rzutujesz to, a że Integer to 4bajty to zrzutuje tylko
//: 41000000
//: I otrzymasz liczbę która w zapisie Hex to 41000000 czyli w Dec 65
s:=integer(a);
writeln(IntToStr(s));
readln;
end.

Przynajmniej tak zrozumialem. To tylko moja teoria. Możesz włączyć debugera zmienną dodać do Watch i ustawić typ jako 'Memory Dump'.
Powodzenia!

mo wiem że można IntToStr(liczbaktóramabyćłańcuchem) ale chciałem sobie przetestować to rzutowanie więc biorę dwa najczęściej konwertowane typy a tu błąd i chciałbym wiedzieć czemu i jakie typy można a jakich nie można rzutować... jest może gdzieś spis typów które mogę rzutować?

W takim wypadku stosuj konwersje (poszukaj artykulu na ten temat).
Rzutowanie to jest sposob na oszukanie kompilatora, ale trzeba wiedziec co sie robi, w Twoim przypadku program nie dziala zgodnie z oczekiwaniami, nie mozna w ten sposob zmienic typu akurat tych zmiennych.

albo jestem głupi albo nie rozumiem...
z tekstu zrozumiałem że:
mam zmienną jakiegoś typu, mam inną zmenną innego typu
funkcja -> jakaś_zmienna := jakiś_typ(zmienna_innego_typu);
zamieni mi zmienną innego typu na zmienną jakiegoś typu

CZYLI...
próbuję:

program Rzut;

{$APPTYPE CONSOLE}

uses
  SysUtils;
var
  a: string;
  s: integer = 111;
begin
  a:=string(s);
  writeln(a);
  readln;
end.

niby powinno wyświetlić 111 ale wyskakuje wyjątek
czyli coś nie rozumiem ale przysięgam że przeczytałem ten tekst wiele razy i tyle samo (no może mniej) próbowałem to co powyżej przedstawiłem

a jak z kolei próbuję

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;
var
  a: string = '111';
  s: integer;
begin
  s:=integer(a);
  writeln(IntToStr(s));
  readln;
end.

to zamiast 111 wyświetla 4227420 :/
o co chodzi???