Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Cast Array[0..x] of Byte in TBytes (https://www.delphipraxis.net/161348-cast-array%5B0-x%5D-byte-tbytes.html)

schwa226 29. Jun 2011 17:39

Cast Array[0..x] of Byte in TBytes
 
Hi!

Ich möchte gerne mit TIdTCPServer Daten an den Client schicken.
Über
Delphi-Quellcode:
AContext.Connection.IOHandler.Write(Buffer, len);
Kann ich TBytes an den Client schicken.

Ich habe aber nun Buffer als Array[0..1023] of Byte;

Nun will Write den Buffer nicht mehr. Und extra immer ein TBytes Array mit Setlength zu setzen, dann die Daten kopieren und diese dann zu schicken ist etwas umständlich.

Wie kann man das richtig Casten damit es keine Probleme gibt?

Uwe Raabe 29. Jun 2011 18:01

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von schwa226 (Beitrag 1109003)
Wie kann man das richtig Casten damit es keine Probleme gibt?

Das kann man nicht casten, da es sich um unterschiedliche Datentypen handelt, die auch ein unterschiedliches Speicherlayout haben.

schwa226 29. Jun 2011 19:53

AW: Cast Array[0..x] of Byte in TBytes
 
Ok, danke!

So gibt es zumindest keinen Crash:
Delphi-Quellcode:
var
  _buffer : TBytes;
  buffer : Array[0..1023] of Byte;
begin

  SetLength(_buffer, Length(buffer));
  _buffer := @buffer[0];
Man spart sich das Memcopy.

Satty67 29. Jun 2011 20:03

AW: Cast Array[0..x] of Byte in TBytes
 
Das kann nicht richtig sein.

Du verlierst den Zeiger auf den dynamisch reservierten Speicher (_buffer). Es sollte ein Speicherleck geben und fast eine Zugriffsverletzung, wenn _buffer irgendwann freigegeben werden soll und buffer kein gültiger Zeiger mehr ist.

Uwe Raabe 29. Jun 2011 20:06

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von schwa226 (Beitrag 1109040)
So gibt es zumindest keinen Crash:
Delphi-Quellcode:
var
  _buffer : TBytes;
  buffer : Array[0..1023] of Byte;
begin

  SetLength(_buffer, Length(buffer));
  _buffer := @buffer[0];
Man spart sich das Memcopy.

Na toll! Man baut sich eine Zeitbombe ein, nur um ein MemCopy zu sparen? Schreib doch besser eine Funktion, die dir aus einem statischen Array ein TBytes macht und der Code wird wesentlich sauberer, lesbarer und weniger fehleranfällig.

Thom 29. Jun 2011 23:08

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1109014)
Das kann man nicht casten, da es sich um unterschiedliche Datentypen handelt, die auch ein unterschiedliches Speicherlayout haben.

Da muß ich leider widersprechen: Auch wenn es sich im programmtechnischen Sinn um verschiedene Typen handelt (dynamisches vs. statisches Array), so liegen dennoch in beiden Fällen die Daten byteweise hintereinander. Damit haben sie sehr wohl das selbe Speicherlayout.

Durch den Umstand, daß die Write-Methode den Parameter ABuffer als Konstante erwartet, wird vom Compiler nur die Anfangsadresse des Arrays übergeben. Und damit ist es völlig egal, ob es sich dabei um den Beginn eines dynamischen oder eines statischen Arrays handelt.

Ein kleines Beispiel:
Delphi-Quellcode:
procedure Test(const ABuffer: TBytes; ALength: Integer);
var
  n: Integer;
  s: String;
begin
  s:='';
  for n:=0 to ALength-1 do
  begin
    if s<>''
      then s:=s+',';
    s:=s+IntToStr(ABuffer[n]);
  end;
  ShowMessage(s);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  n: Integer;
  a: array[0..9] of Byte;
  b: TBytes;
begin
  //dynamisches Array:
  SetLength(b,10);
  for n:=Low(b) to High(b) do
    b[n]:=n;
  Test(b,10);
  //statisches Array:
  for n:=Low(a) to High(a) do
    a[n]:=n;
  Test(TBytes(@a[0]),10); //<- Typecast
end;
Das heißt: Ein Typecast ist sehr wohl möglich. Ob er auch sinnvoll ist, steht auf einem ganz anderen Blatt... :wink:

schwa226 30. Jun 2011 06:50

AW: Cast Array[0..x] of Byte in TBytes
 
Nur zum Beruhigen: ich habe es so eh nicht umgesetzt!
Bei meinen Versuchen war das die einzige Methode wo es keinen Memory Fehler gab :oops:

Satty67 30. Jun 2011 07:25

AW: Cast Array[0..x] of Byte in TBytes
 
@schwa266: Sowas hat jeder mal versucht, besonders wenn man die Verwandschaft (und Compiler-Unterstützung) von String und PChar kennt, will man das gerne mal auf andere Bereiche übertragen.

Zitat:

Zitat von Thom (Beitrag 1109079)
Ein Typecast ist sehr wohl möglich. Ob er auch sinnvoll ist

Ein Typecast ist mit einem untypisierten Pointer immer möglich, die Frage ist nicht ob er sinnvoll ist, sondern ob er richtig ist:

Delphi-Quellcode:
procedure Test(ABuffer: TBytes; ALength: Integer);
var
  n: Integer;
  s: String;
begin
  ShowMessage(Format('From %d To %d', [Low(ABuffer), High(ABuffer)]));
"From 0 To <Random>"
Wie das Beispiel zeigt ist der Typecast nicht korrekt und nur im begrenzten Fall problemlos.

Thom 30. Jun 2011 10:58

AW: Cast Array[0..x] of Byte in TBytes
 
@Satty67:

Ich hatte auf die Behauptung von Uwe Raabe reagiert - nicht auf Deine. Und es ging bei der Frage des Threaderstellers darum, ob es in dem konkteren Fall möglich ist.

Noch einmal ausführlich für Dich, was ich mit meiner Bemerkung gemeint hatte:

Selbstverständlich ist es eine bekannte Tatsache, daß ein Pointer ein Pointer bleibt und der Typecast nur ein (unsauberes) Mittel ist, um den Compiler dazu zu bringen, seine Arbeit ohne Fehlermitteilung fortzusetzen. Man muß also sehr genau wissen, was man tut und sich überlegen, welche Delphi-Funktionen mit dem gecasteten Pointer eingesetzt werden können.
Genau aus diesem Grund hatte ich geschrieben, daß man sich die Frage stellen sollte, ob ein Cast sinnvoll ist - also ob er das gewünschte Ergebnis liefert. Geht es zum Beispiel um eine hohe Geschwindigkeit, wäre das ständige Kopieren von Puffern kontraproduktiv.
Natürlich wäre es günstiger - falls möglich - , das statische Array gleich durch ein dynamisches Array zu ersetzten und damit potentiellen Problemen aus dem Weg zu gehen.

Hatte ich an irgend einer Stelle behauptet, daß ein derartiger Cast immer und in jedem Fall sinnvoll ist? Ich kann mich nicht daran erinnern.
Es ist also von Dir absolut überflüssig, in einer derart belehrenden Art und Weise zu schreiben und andere für dumm zu halten.
Aber das scheint hier im Forum leider eine weit verbreitete Unsitte zu sein. Da wird nicht auf konkrete Fragen geantwortet sondern lieber aus - nahezu - jedem Thread eine Prizipiendiskussion gemacht, um sich selbst zu profilieren. Sehr bezeichnend und sehr bedauerlich.

Uwe Raabe 30. Jun 2011 12:32

AW: Cast Array[0..x] of Byte in TBytes
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Thom (Beitrag 1109079)
Auch wenn es sich im programmtechnischen Sinn um verschiedene Typen handelt (dynamisches vs. statisches Array), so liegen dennoch in beiden Fällen die Daten byteweise hintereinander. Damit haben sie sehr wohl das selbe Speicherlayout.

Das gilt sicher für die Nutzdaten, nicht aber für die Länge des Arrays und die Referenzzählung. Selbst wenn das im aktuellen Fall nicht relevant sein sollte, besteht immer die Gefahr, das dieses Konstrukt in einer zukünftigen Version nicht mehr funktioniert.

Das tatsächliche Speicherlayout kann man hier nachlesen. Das dynamische Array ist also ein Pointer auf die Nutzdaten, wobei der Bereich vor den Nutzdaten aber noch zum Array gehört. Demnach ist der Cast auf das statische Array einfach nur brandgefährlich, weil die 8 Byte vor dem Array nun als Größe und als Referenzzähler interpretiert werden. In dem Längenfeld kann alles möglich drinstehen und es kann sich sogar jederzeit ändern - heißt: die verwendete Länge passt nicht zur wirklichen Größe des Arrays. Dann kann es auch noch passieren, daß der Compiler dann noch bei der Referenzzählung das Array einfach frei gibt (das wird spaßig). Wenn es nicht crasht ist das einfach nur Glück.

Beiliegendes Projekt zeigt das ganz deutlich - und es crasht auch beim Beenden.

Insofern bleibe ich bei meiner Aussage, daß das Speicherlayout unterschiedlich ist.

himitsu 30. Jun 2011 12:38

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1109205)
Das gilt sicher für die Nutzdaten, ...

Genau aus diesem Grund wäre ein Cast möglich, aber nur andersrum.

Delphi-Quellcode:
TBytes
nach
Delphi-Quellcode:
Array[0..x] of Byte
läßt sich Casten, da die nötigen Daten des statischen arrays im dynamischen enthalten sind, solange das dynamische Array mindestens so groß ist, wie das Statische.
Aber in diesem Fall kommt man um ein Umkopieren nicht drumrum.

Deep-Sea 30. Jun 2011 13:03

AW: Cast Array[0..x] of Byte in TBytes
 
Der TIdIOHandler nimmt aber auch u.a. Streams an. Ich habe mir vor einiger Zeit schon eine kleine Klasse von TCustomMemoryStream abgeleitet, der ich im Konstruktor einen bereits bestehenden Puffer - wie z.B. ein statisches Array - und dessen Länge übergeben kann. So wandelt man irgendwelche Daten ohne umkopieren in einen Stream :stupid:
Ob es hier aber nicht vlt. einfacher und sinnvoller wäre, den aufrufenden Code an TBytes anzupassen, kann ich nicht beurteilen.

Thom 30. Jun 2011 13:14

AW: Cast Array[0..x] of Byte in TBytes
 
@Uwe Raabe:

Die Nutzdaten haben das selbe Layout: Einfach 1024 Bytes hintereinander. Die Verwaltungsinformationen (auf die Delphi intern zugreift) sind für diese Speicherbereiche unterschiedlich.
Und im konkteten Fall der Write-Methode sind nur die Nutzdaten relevant. Genau aus diesem Grund muß ja auch die Länge des Speicherbereichs mit übergeben werden. Und damit ist ein Typecast im Gegensatz zu Deiner Behauptung im konkreten Falle sehr wohl möglich.

Sorry - aber es wie im Kindergarten... :lol:
Jeder will hier auf Biegen oder Brechen Recht behalten. Ist irgendwie lächerlich und schade um die vergeudete Zeit.. :stupid:

Und wie überflüssig das Ganze ist, sieht man am Beitrag des Fragestellers: Es hat bei ihm (im speziellen Fall) funktioniert. Auch bei
Delphi-Quellcode:
ReportMemoryLeaksOnShutdown:=true;
treten (bei mir) keine Speicherfehler auf.

Aber die Theoretiker beharren auf ihrer Meinung... :stupid:


@Deep-Sea:

Interessante Idee! :thumb:

Deep-Sea 30. Jun 2011 13:33

AW: Cast Array[0..x] of Byte in TBytes
 
Auch wenn ich mich ungern in die Schussbahn einer so hitzigen Diskussion begebe, wollte ich es trotzdem los werden:
Zitat:

Zitat von Thom (Beitrag 1109226)
Es hat bei ihm (im speziellen Fall) funktioniert.

Die zweite Zeile in
Delphi-Quellcode:
AContext.Connection.IOHandler.Write
sieht so aus:
Delphi-Quellcode:
LLength := IndyLength(ABuffer, ALength, AOffset);
.
Und die zweite Zeile der Funktion IndyLength enthält wiederum das:
Delphi-Quellcode:
LAvailable := IndyMax(Length(ABuffer)-AIndex, 0);
Hier wird also auf die Länge des dyn. Arrays mittels Length zugegriffen. Das das gut geht ist reine Glückssache ...
Dein Code funktioniert also, sofern man die Funktion selbst geschrieben hat und auf Length verzichtet. Allgemein ist es aber leider eine tickende Zeitbombe ...

himitsu 30. Jun 2011 13:43

AW: Cast Array[0..x] of Byte in TBytes
 
PS: Ist denn unbedingt ein statisches Array notwendig?

Einfach TBytes nehmen und am Anfang ein
Delphi-Quellcode:
SetLength(a, 1000);
und schon kann man das Array direkt übergeben.

Wenn irgendwo, in deinem Code, sowas wie @a vorkommt, dann dieses durch @a[0] ersetzen und das Selbe auch noch bei Var-Parametern.


Zitat:

Länge des Speicherbereichs
Man gibt nicht die Länge des Speicherbereichs, sondern den Abschnitt in dem Array an, welchen man versenden will und dieses wird dann nochmal von Indy geprüft, wobei es natürlich auf die originalen Daten zugreift.

Deep-Sea 30. Jun 2011 13:46

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von himitsu (Beitrag 1109235)
[...] dann dieses durch @a[0] ersetzen [...]

Oder besser gleich immer
Delphi-Quellcode:
@a[Low(a)]
schreiben, dann passt es immer, auch für statische Arrays die nicht mit 0 beginnen :stupid:

Thom 30. Jun 2011 14:38

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von Deep-Sea (Beitrag 1109233)
Hier wird also auf die Länge des dyn. Arrays mittels Length zugegriffen. Das das gut geht ist reine Glückssache ...
Dein Code funktioniert also, sofern man die Funktion selbst geschrieben hat und auf Length verzichtet. Allgemein ist es aber leider eine tickende Zeitbombe ...

Das akzeptiere ich ohne Widerspruch! :lol:
Deshalb ja auch meine Bemerkung
Zitat:

Zitat von Thom (Beitrag 1109079)
Ein Typecast ist sehr wohl möglich. Ob er auch sinnvoll ist, steht auf einem ganz anderen Blatt... :wink:


Satty67 30. Jun 2011 14:39

AW: Cast Array[0..x] of Byte in TBytes
 
Zitat:

Zitat von Thom (Beitrag 1109171)
Es ist also von Dir absolut überflüssig, in einer derart belehrenden Art und Weise zu schreiben und andere für dumm zu halten.

Ich sehe in meinem Post nur einen sachlichen Hinweis. Was Du alles da rein interpretierst ist mir schleierhaft.

Thom 30. Jun 2011 14:55

AW: Cast Array[0..x] of Byte in TBytes
 
Ich weiß nicht, wie alt Du bist und ob Du viel mit andere Menschen zu tun hat (Kinder, Schüler, Praktikanten, Angestellte,...).
Ist aber eigentlich auch egal: Aus meiner Sicht ist oftmals der Ton wichtiger als der Inhalt. Und genau dieser Umgangston läßt in vielen Foren arg zu wünschen übrig...
Aber das ist Offtopic: Wenn Du Interesse hat, können wir das auch gern per PM besprechen.

p80286 30. Jun 2011 15:02

AW: Cast Array[0..x] of Byte in TBytes
 
Hallo....

nu kommt doch bitte auf den Boden zurück. Können wir uns darauf einigen, daß Typecasting ein ganz heißes Eisen ist, und daß man damit sehr zurückhaltend und vorsichtig umgehen sollte?
(und Pointer gehören in die gleiche Kathegorie?)

Gruß
K-H

Thom 30. Jun 2011 15:36

AW: Cast Array[0..x] of Byte in TBytes
 
Kein Problem damit. :lol:
Genau das sage ich schon seit x Beiträgen: Es ist möglich, aber nicht immer sinnvoll... (ist jetzt bestimmt schon das vierte oder fünfte mal).

Und damit schließe ich meine Senftube, damit der Thread nicht durch einen Moderator geschlossen wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz