Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Größe bei dyn. Arrays automatisch? (https://www.delphipraxis.net/175049-groesse-bei-dyn-arrays-automatisch.html)

jensen82 27. Mai 2013 14:52

Delphi-Version: 2010

Größe bei dyn. Arrays automatisch?
 
Hallo!

Ich habe schon einige Jahre Programmiererfahrung in anderen Sprachen und bin vor kurzem zu Delphi "gewechselt". Klar...entweder man kann programmieren oder eben nicht.
Mir ist allerdings etwas aufgefallen:

Ich lese Hardware-Infos via WQL und WMI aus und bekomme via OLE und Wbem-Script Daten zurück (Variant). Damit wird ein Record gefüllt.
Hier werden u.a "array UINT16" zurückgegeben. Im Record habe ich daher data : array of Integer; stehen. Das Tolle ist...es geht, ohne SetLength() zu verwenden.

Meine Frage ist: Warum macht Delphi das autom. und warum wird immer empfohlen via SetLength die Größe anzugeben?

Ist die Variante sicher? Also ohne SetLength ?

Hier mal ein Code-Ausschnitt:

Delphi-Quellcode:
TDiskInfo = record
    Availability: Integer; // Uint16
    BytesPerSector: Integer; // Uint32
    Capabilities: array of Integer; // Array of Uint16

// Hier jetzt die Zuweisung:
if not VarIsNull(FWbemObject.Capabilities) then
        begin
          disk.Capabilities := FWbemObject.Capabilities;
end

// klappt ohne Probleme
Ich würde mich über Konstruktives freuen :-)

Und bitte nicht lachen...der Wechsel zu Delphi ist noch nciht ganz abgeschlossen.

Danke sehr!

Klaus01 27. Mai 2013 15:03

AW: Größe bei dyn. Arrays automatisch?
 
Hallo,
meines Wissen übergibst Du hier
Delphi-Quellcode:
disk.Capabilities := FWbemObject.Capabilities;
die Adresse von einem anderen Array und nicht den Inhalt des anderen Arrays.


Grüße
Klaus

Medium 27. Mai 2013 15:03

AW: Größe bei dyn. Arrays automatisch?
 
Das ist absolut gefährlich! Ein dynamisches Array ist zunächst nur ein Pointer an eine Adresse. Wenn Delphi nicht gesagt bekommt, wie viele Bytes dahinter für das Array zu reservieren sind, kann/wird dir der Delphi Speichermanager diesen Bereich mit allen möglichen anderen Dingen aus deinem Programm beschreiben - oder schlimmer noch: Es hat dies schon getan, jetzt kommt aber die API Funktion daher - die nichts davon weiss, dass der Speicher schon anders benutzt wird - und jodelt dort fröhlich seine Ausgaben hin.
Das geht genau so lange gut, wie dein Programm zufällig nichts weiteres mit dem Speicher ab der Array-Position macht. Und NUR dann. Damit lassen sich die wildesten Fehler herstellen, an Stellen die man erst nach Tagen/Wochen des Suchens mit dem Array in Zusammenhang bringen könnte.

IMMER die Größe vor der Benutzung setzen!!

Uwe Raabe 27. Mai 2013 15:10

AW: Größe bei dyn. Arrays automatisch?
 
Zitat:

Zitat von Medium (Beitrag 1216581)
Das ist absolut gefährlich!

Ist es nicht!

Bei der Zuweisung einer Varianten an eine Variable eines definierten Typs versucht der Compiler eine implizite Umwandlung. Im Fall eines dynamischen Arrays wird _VarToDynArray aufgerufen, das mittels DynArrayFromVariant eine Umwandlung vornimmt. Sollte das nicht funktionieren wird eine EVariantTypeCastError-Exception ausgelöst.

Der schöne Günther 27. Mai 2013 15:14

AW: Größe bei dyn. Arrays automatisch?
 
Ignoriert mich

Medium 27. Mai 2013 15:22

AW: Größe bei dyn. Arrays automatisch?
 
Gürks, OLE-Geschlumpfe. Okay, da habe ich etwas zu oberflächlich gelesen. Was aber von meiner Aussage oben bleibt ist, dass sie zutrifft, wenn man ohne "magische" Resourcen hantiert.

baumina 27. Mai 2013 15:28

AW: Größe bei dyn. Arrays automatisch?
 
Zitat:

Zitat von Medium (Beitrag 1216589)
Gürks, OLE-Geschlumpfe. Okay, da habe ich etwas zu oberflächlich gelesen. Was aber von meiner Aussage oben bleibt ist, dass sie zutrifft, wenn man ohne "magische" Resourcen hantiert.

Ein Variant ist magisch?

Uwe Raabe 27. Mai 2013 15:34

AW: Größe bei dyn. Arrays automatisch?
 
Zitat:

Zitat von Medium (Beitrag 1216589)
Gürks, OLE-Geschlumpfe. Okay, da habe ich etwas zu oberflächlich gelesen. Was aber von meiner Aussage oben bleibt ist, dass sie zutrifft, wenn man ohne "magische" Resourcen hantiert.

Das hat gar nichts mit OLE zu tun, sondern damit wie Delphi mit Variants umgeht. Der folgende Code ist also durchaus korrekt und ungefährlich:

Delphi-Quellcode:
var
  A: array of Integer;
  V: Variant;
  I: Integer;
begin
  V := VarArrayCreate([0,9], varInteger);
  for I := 0 to 9 do
    V[I] := I;
  A := V;
  for I := 0 to 9 do
    Assert(V[I] = I);

  VarClear(V);
  V := A;
  for I := 0 to 9 do
    Assert(V[I] = I);

end;

Medium 27. Mai 2013 16:19

AW: Größe bei dyn. Arrays automatisch?
 
Aus pascalscher Sicht sind Variants durchaus "magisch", da mit vergleichsweise viel Compiler Magic ausgestattet, und (u.a.) die Typstrenge aufweichend. Und gerade variante Arrays (für die es ohne OLE imho anfangs wenig Bedarf in Delphi gegeben hätte) bringen einfach viele Automatismen mit, die die dynamischen Arrays, über die man sich normalerweise in Delphi unterhält, einfach nicht haben. Ich hoffe man versteht mich jetzt richtiger.

jensen82 27. Mai 2013 18:10

AW: Größe bei dyn. Arrays automatisch?
 
Hey!

Also ist das in Ordnung... ? Aber warum in aller Welt muss ich die Länge des Arrays nicht angeben?
Wäre es generisch, z.B. List oder vector aus C++ wäre ja mit .Add(meinVar) alles fein. Kann mir das jemand erklären?

Hier nochmal ein wenig Code:

Delphi-Quellcode:
function GetAllDisks(sHostName: String; sUserName: String;
  sPassword: String): TDiskInfoList;
const
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator: OLEVariant;
  FWMIService: OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject: OLEVariant;
  oEnum: IEnumvariant;
  iValue: LongWord;
  disk: TDiskInfo;
  diskList: TDiskInfoList;
begin
  try
    CoInitialize(nil);
    try
      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      FWMIService := FSWbemLocator.ConnectServer(sHostName, 'root\CIMV2',
        sUserName, sPassword);
      FWbemObjectSet := FWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive',
        'WQL', wbemFlagForwardOnly);
      oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumvariant;
      while oEnum.Next(1, FWbemObject, iValue) = 0 do
      begin
        //if not VarIsNull(FWbemObject.Availability) then
          disk.Availability := FWbemObject.Availability;

        if not VarIsNull(FWbemObject.BytesPerSector) then
          disk.BytesPerSector := FWbemObject.BytesPerSector;

        if not VarIsNull(FWbemObject.Capabilities) then
          disk.Capabilities := FWbemObject.Capabilities;
Letztendlich gibt die Funktion eine List zurück.

Ich danke euch vielmals.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:59 Uhr.
Seite 1 von 2  1 2      

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