eeee... takie tam bajty

0

Dzień dobry chciałem prosić o jakąś długą wypowiedź,
chodzi o to że mało klawiatury nie pogryzłem i nic z tego nie kumam
w SPACJA końcu doszedłem do celu <font color="red">najprostrzą</span> drogą, ale mimo tego
nie wiem o co w tym chodzi ?

Chciałem plik binarny wstawić do Stringa no i ...

function FileToString(FName : String) : String;
var
F : File of Byte;
Buf : Array of Char;
begin
AssignFile(F, FName);
try
Reset(F);
SetLength(Buf, FileSize(F));
// SizeOf(Buf) jest równe 4, dlaczego ?
BlockRead(F, Buf[0], SizeOf(Buf));
Result := PChar(Buf);
// wpisałem to przypadkiem, czy to jest OK ?
finally
CloseFile(F);
end;
end;

Dlaczego np. można przypisać do stringa tablice normalną
ale nie da się dynamicznej, wydawało mi się że String
to coś w rodzaju dynamicznego Array of Char, no i dlaczego
funkcja PChar() zadziałała ?

No i już zupełnie BTW to czym się różni przesyłanie
dajmy na to w najprostrzym ClientSocket , binarne i textowe ?
pomijając to że w SendBuf trzeba wstawić rozmiar tego bufora
to przecieŻ server może go odebrać po prostu jako ReceiveText.
Więc na co rozróżnienie ASCII i Binary w jakimś IdFTP skoro
to i tak tylko ciągi zer i jedynek ? Są jakieś różnice ?

0

SizeOf(Buf) jest równe 4, dlaczego ?

Tablice dynamiczne są w rzeczywistości wskaźnikami do pamięci.
Wskaźnik to liczba typu DWord i dlatego ma 4 bajty. Należałoby użyć raczej Length.

Dlaczego np. można przypisać do stringa tablice normalną
ale nie da się dynamicznej, wydawało mi się że String
to coś w rodzaju dynamicznego Array of Char, no i dlaczego
funkcja PChar() zadziałała ?

String to jest array of char, ale... Ma jeszcze dodatkowo pole nr 0, które jest długością łańcucha. Natomiast array of char to jest to samo co PChar o ile na samym końcu jest znak o kodzie 0. W twoim przypadku chyba wstawianie 0 na koniec jest zbędne, bo PChar zrzutuje to chyba prawidłowo.

No i już zupełnie BTW to czym się różni przesyłanie
dajmy na to w najprostrzym ClientSocket , binarne i textowe ?

Jak już wiele razy podkreślałem, na sieciach się nie znam, ale wiem co się dzieje, jak się otwiera plik binarny jako tekst. Załóżmy, że trafisz na kod 0 lub 27. Co w takim wypadku zrobi program wczytujący tekst? Zakończy wczytywanie. Prawdopodobnie z tego samego powodu jest tryb tekstowy i binarny w FTP.

0

Sprawa jest prosta i byla juz opisywana na forum :)))

String jest dynamiczny, dlatego jest reprezentowany przez wskaznik, ktory ma 4 bajty. I zeby poznac wielkosc stringu (jak i tablicy dynamicznej) uzywamy funkcji Length, a nie SizeOf. SizeOf zawsze zwroci 4 (a w systemach 64-bitowych zapewne 8). Dlatego na przyklad w rekordach przeznaczonych do zapisu do pliku nie mozna stosowac jako pol stringow: trzeba uzywac krotkie (statyczne) stringi albo statyczne array of char.

Oto poprawny (wyprobowany) kod

function FileToString(FName : String) : String;
var
F : File of Byte;
begin
AssignFile(F, FName);
try
Reset(F);
SetLength(Result, FileSize(F));
// SizeOf(Buf) jest równe 4, dlaczego ? dlatego jak wyzej
BlockRead(F, Result[1], Length(Result));
//albo BlockRead(F, Result[1], FileSize(F));
finally
CloseFile(F);
end;
end;

Dlaczego np. można przypisać do stringa tablice normalną
ale nie da się dynamicznej,

mozna

s:=string(a); //gdzie s to string, a - statyczna array of char

0

Dziękuję wam serdecznie za fachowe odpowiedzi [hurra]

hmmm... czyli dlatego ciągle była gatka o tym że
tablice dynamiczną do BlockRead wprowadza się z indeksem
zero, bo bez indeksu trafiłby do funkcji wskaźnik, a tak
wprowadzane jest to konkretne miejsce w pamięci

a mógłby ktoś jeszcze bardziej fizycznie
opisać pojęcia wskaźnik i miejsce w pamięci ?

rozumiem pq że tam jest Result[1] bo tym że Resultem ma być
String, który jak wspomniał Dryobates jest Array of Char,
gdzie w polu 0 ma być zapisana długość, więc BlockRead ma zapisać
od pola numer 1, a długość tego stringa do pola 0 zapisują skrzaty ?

eeeee... no i array of char to stringa, czyli pole zero
też jest char czyli ma 8 bajtów, czyli nie da się w tym polu
zapisać liczby wyższej od 255, czyli string nie może być dłuższy
niż 255 znaków, ale jeśli PChar() ma inny system informowania o
swoim końcu (Chr(0)) to mógł by być dłuższy a nie jest ?

No i poco jest PChar i String ? nie wystarczyła by jedna forma ?
Są jakieś konkretne powody ?

0

rozumiem pq że tam jest Result[1] bo tym że Resultem ma być
String, który jak wspomniał Dryobates jest Array of Char,
gdzie w polu 0 ma być zapisana długość, więc BlockRead ma zapisać
od pola numer 1, a długość tego stringa do pola 0 zapisują skrzaty ?

Dryobates chyba troszke pomylil. Dlugosc stringa nie moze byc zapisywana w polu zero, bo pole ma jeden bajt a string ma maks dlugosc 231-1 (dla AnsiString, 230-1 dla WideString). Dlugosc jest zapisywana w polu zero w starych pascalowskich statycznych stringach deklarowanych w Delphi jako ShortString albo string[liczba_do_255], ktore maja maks dugosc 255.

Dlugi string jest zapisany jako wskaznik. Jesli lancuch jest pusty, to wskaznik ma wartosc nil i na tym sprawa sie konczy. Jesli lancuch ma zawartosc, wtedy wskaznik wskazuje na poczatek dynamicznie przydzielonego obszaru pamieci zawierajacego tresc lancucha. Natomiast 8 bajtow przed miejscem wskazywanym przez wskaznik zajmują 32-bitowe pole trzymajace dlugosc i 32-bitowy licznik referencji.

Licznik referencji jest wykorzystywany dla zaoszczedzenia czasu i pamieci. Lancuchy sa wskaznikami, wiec jesli sa identyczne (bylo przypisanie s2:=s1) wtedy moga po prostu wskazywac na ten sam obszar pamieci zawierajacy te sama tresc, nie trzeba tworzyc 2 identycznych obszarow pamieci zawierajacych to samo. Licznik referencji pamieta ile stringow (wskaznikow) wskazuje na dana tresc. Jezeli lancuch jest kasowany (s1:=nil) albo jest zmieniona jego tresc (s1:=s3) wtedy licznik referencji starej tresci jest zmniejszany. Gdy licznik referencji dojdzie do zera, oznacza to, ze zaden lancuch(wskaznik) nie wskazuje juz tej pamieci i pamiec jest zwalniana.
Ponadto, jesli wykonujemy s1[1223]:='x' zeby zmienic jedna litere, wtedy jest sprawdzany licznik referencji. Jesli jest =1, wtedy podmieniana jest ta litera i rzecz konczy sie szybko. Tylko jesli jest >1, wtedy trzeba utworzyc nowa kopie lancucha, bo dotychczasowa byla uzywana przez >1 lancuch (warto tu dodac, ze tablice dynamiczne nie stosuja takiego mechanizmu (zwanego copy-on-write), jesli zrobimy A:=B; (A i B to tablice dynamiczne) a potem A[213]:=7; to B[213] tez stanie sie rowne 7). (a wszystko to jest w helpie do Delphi...)

Z powyzszego wynika, ze nie ma przeszkody by dynamiczne lancuchy byly indeksowane od zera (jak tablice dynamiczne) a nie od 1 (jak krotkie lancuchy). Przypuszczam, ze zdecydowano sie na numerowanie od 1, by uproscic pisanie i korzystanie z procedur dzialajacych na lancuchach. Moga one bez modyfikacji czy przeciazania przyjmowac krotkie i dynamiczne lancuchy i przetwarzac je na tych samych zasadach.

0

Dryobates chyba troszke pomylil. Dlugosc stringa nie moze byc zapisywana w polu zero, bo pole ma jeden bajt a string ma maks dlugosc 231-1 (dla AnsiString, 230-1 dla WideString). Dlugosc jest zapisywana w polu zero w starych pascalowskich statycznych stringach deklarowanych w Delphi jako ShortString albo string[liczba_do_255], ktore maja maks dugosc 255.

Święta racja. Mój błąd. Pole 0 w pascalowych stringach. Tutaj można powiedzieć, że to też jest pole 0 (bo jest przecież przed całym tekstem) ale to byłoby naginanie rzeczywistości :)

A co do wskaźnik i miejsce w pamięci to tylko po krótce łopatologicznie (i znów kłania się artykuł o podstawach, którego nie mam kiedy napisać)
Pamięć to zestaw pudełek, które mogą zawierać jakieś elementy. Dla ułatwienia przyjmijmy, że są to liczby. Pudełka są ustawione jeden za drugim i są ponumerowane kolejnymi liczbami całkowitymi.
Załóżmy, że w pudełku nr 1 umieszczę sobie liczbę 5.
W tym przypadku mamy:
var
a: Integer;
a := 5;
Gdzie a to jest pudełko nr 1 i jego zawartością jest 5.
Teraz załóżmy, że w pudełku nr 2 umieścimy nr pudełka a, czyli 1.
Wobec tego:
var
b: Pointer;
b := 1;
gdzie b to jest komórka nr 2 (literki tylko ułatwiają nam rozróżnienie).
Teraz stan pamięci wygląda tak:
Nr pudełka | Zawartość | Nazwa
1 | 5 | a
2 | 1 | b
Czyli instrukcja:
Write(a);
Wypisze zawartość pudełka a, czyli komórki o nr 1. Efektem będzie 5.
Instrukcja:
Write(b);
Wypisze zawartość pudełka b, czyli komórki o nr 2. Efektem będzie 1.
Instrukcja:
b := a;
Zapisze w pudełku b zawartość pudełka a (czyli 5), ale instrukcja:
b := @a;
Zapisze w pudełku b nr pudełka b (czyli 1);
Tak samo w drugą stronę.
Write(b^);
wypisze zawartość pudełka o numerze zapisanym w b. Czyli b^ = a. Z tego mamy w efekcie liczbę 5.

A jeszcze słówko dlaczego powiedziałem, że przyjmujemy, że to są liczby. Jak to powiedział któryś z matematyków "wszystko jest liczbą".
Równie dobrze można przyjąć, że np. 1 oznacza kolor czerwony, a 2 niebieski, albo że 5 to jest woda, a 10 to jest powietrze lub cokolwiek inne. Wszystko jest tylko kwestią umowy.

0

Dziękuje wam ponownie i serdecznie, teraz to już nawet czuje się
na siłach żeby spróbować podejść ponownie do C, tam zawsze mnie
te wskaźniki odpychały, nie miałem nawet pojęcia że w Delphi też
coś takiego może być, naszczęście nie rzuca się w oczy tak bardzo :-D

0

Dziękuje wam ponownie i serdecznie, teraz to już nawet czuje się
na siłach żeby spróbować podejść ponownie do C, tam zawsze mnie
te wskaźniki odpychały, nie miałem nawet pojęcia że w Delphi też
coś takiego może być, naszczęście nie rzuca się w oczy tak bardzo :-D

To lepiej zamiast C weź się za wskaźniki w Asm. Tam ich w ogóle nie zauważysz (bo nawet nie będziesz wiedział, że ich używasz).

1 użytkowników online, w tym zalogowanych: 0, gości: 1