Enum als Bereich für Arrays

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
jammernich
Beiträge: 25
Registriert: Di 5. Nov 2024, 22:36
OS, Lazarus, FPC: Win11, Lazarus 3.8
CPU-Target: x86_64bit

Enum als Bereich für Arrays

Beitrag von jammernich »

Code: Alles auswählen

type
  TLogPriorities = (lpUNKOWN, lpVERBOSE, lpDEBUG, lpINFO, lpWARN, lpERROR, lpCRITICAL);
Das probiere ich gerade aus, funktioniert auch Klasse! Der erste Index ist automatisch 0.

Wie bekomme ich den Integer-Wert von einem Index heraus?

Code: Alles auswählen

type
  TLogPriorityInfo = Array[TLogPriorities] OF String;

const 
  CLogPriorityDesc : TLogPriorityInfo =
  ('UNKNOWN', 'VERBOSE', 'DEBUG', 'INFO', 'WARNING',
   'ERROR', 'CRITICAL');  
Das Array CLogPriorityDesc hat nun einen Index mit Typ. Ich brauche das um für den Benutzer Einstellungen anzeigen zu können. Gibt es eine Möglichkeit durch-zu-iterieren? Wenn das Array einen numerischen Index hätte (z.B. Typ Longint) dann könnte ich das ja einfach mit einer for Schleife durchschreiten lassen.

Code: Alles auswählen

//so etwa
for i:=0 to n do Writeln(CLogPriorityDesc[i]) //funktioniert natürlich nicht!

Andy Nightingale
Beiträge: 179
Registriert: Mo 13. Jan 2025, 12:11

Re: Enum als Bereich für Arrays

Beitrag von Andy Nightingale »

Ich kenn mich zwar nicht aus.- bin eben noch Anfänger aber vielleicht hilft das: https://wiki.freepascal.org/Enum_type
var
AktuellesLevel: TLogPriorities;
begin
// Setze das Level auf DEBUG
AktuellesLevel := lpDEBUG;

// Hole den Integer-Wert
Wert := Ord(AktuellesLevel); // Gibt 2 zurück

// Oder vergleiche direkt mit einem Integer
if Ord(AktuellesLevel) = 2 then
writeln('Aktuelles Level ist DEBUG');
end;

jammernich
Beiträge: 25
Registriert: Di 5. Nov 2024, 22:36
OS, Lazarus, FPC: Win11, Lazarus 3.8
CPU-Target: x86_64bit

Re: Enum als Bereich für Arrays

Beitrag von jammernich »

@Andy Nightingale: Frage 1 beantwortet. Danke :)
---
Zur 2. Frage: für das Enum ein Array anlegen mit index?

Code: Alles auswählen

const
  count = 7;
  CLogPriorityDesc : Array[0..count-1] of String =
  ('UNKNOWN', 'VERBOSE', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL');

Benutzeravatar
theo
Beiträge: 10856
Registriert: Mo 11. Sep 2006, 19:01

Re: Enum als Bereich für Arrays

Beitrag von theo »

jammernich hat geschrieben: Mo 31. Mär 2025, 20:53

Code: Alles auswählen

//so etwa
for i:=0 to n do Writeln(CLogPriorityDesc[i]) //funktioniert natürlich nicht!
Kann man typecasten: CLogPriorityDesc[TLogPriorities(i)]

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Enum als Bereich für Arrays

Beitrag von Warf »

Warum nicht einfach:

Code: Alles auswählen

type
  TTestEnum = (A, B, C, D);

var
  arr: Array[TTestEnum] of Integer;
  e: TTestEnum;
begin
  for e in TTestEnum do
    arr[e] := 0;
end.
Oder:

Code: Alles auswählen

  for e:=Low(TTestEnum) to High(TTestEnum) do
    arr[e] := 0;  
Aber du kannst Enums einfach zu den Unterliegenden Integern konvertieren mittels ord:

Code: Alles auswählen

WriteLn(Ord(A)); // 0
WriteLn(TTestEnum(0)); // A

Frank Ranis
Beiträge: 210
Registriert: Do 24. Jan 2013, 21:22

Re: Enum als Bereich für Arrays

Beitrag von Frank Ranis »

Hi ,

so was habe ich neulich auch gebraucht.

In der Unit TypInfo gibt es dazu die Funktion GetEnumName .

Hier mal ein Beispiel-Projekt .

Gruß

Frank

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Spin, StdCtrls,
  TypInfo;

type
  TLogPriorities = (lpUNKOWN, lpVERBOSE, lpDEBUG, lpINFO, lpWARN, lpERROR, lpCRITICAL);

  { TForm1 }

  TForm1 = class(TForm)
    Label1: TLabel;
    SpinEdit1: TSpinEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure SpinEdit1Change(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

 function TLogPrioritiesToString( value: TLogPriorities ): string;
 function StringToTLogPriorities(const value: string):TLogPriorities;

implementation

{$R *.lfm}

// Wandelt Enum-Typ in Text
function TLogPrioritiesToString( value: TLogPriorities ): string;
begin
    result := GetEnumName(typeInfo(TLogPriorities), Ord(value));
end;

// Wandelt Text in Enum-Typ
function StringToTLogPriorities(const value: string):TLogPriorities;
begin
  result := TLogPriorities(GetEnumValue(Typeinfo(TLogPriorities),value));
end;

{ TForm1 }

// Je nach Value vom Spinedit den Text von TLogPriorities ausgeben
procedure TForm1.SpinEdit1Change(Sender: TObject);
var tl:TLogPriorities;
    i:integer;
    s:string;
begin
 i:=SpinEdit1.Value;
 tl:=TLogPriorities(i);
 // Kompletter Text des TLogPriorities-Eintrages incl. dem 'lp'
 s:=TLogPrioritiesToString(tl);
 // Das 'lp' entfernen
 s:=s.Replace('lp','');
 label1.Caption:=s;
end;

// Beim Anzeigen der Form einmal ausgeben
procedure TForm1.FormShow(Sender: TObject);
begin
 SpinEdit1Change(nil);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 // Anzahl von TLogPriorities-Einträgen und Spinedit.MaxValue anpassen
 SpinEdit1.MaxValue:=ord(high(TLogPriorities));
end;

end.                                 
enum2text.zip
(139.85 KiB) 38-mal heruntergeladen
www.flz-vortex.de

Benutzeravatar
Zvoni
Beiträge: 363
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Enum als Bereich für Arrays

Beitrag von Zvoni »

Wozu TypInfo??

Denk ich jetzt zu sehr um die Ecke?

Code: Alles auswählen

program Project1;
Type
  TZahl = (null, eins, zwei, drei, vier);
Var
  z:TZahl;
  i:Integer;
  s:String;
begin
  For i:=0 To 4 Do
    Begin
      z:=TZahl(i);
      WriteStr(s,z);      //Schreibe Enum-Bezeichner in String um
      Writeln('String=',s,' - Wert=',Ord(z));
    end;
  Readln;
end.
Ergibt
String=null - Wert=0
String=eins - Wert=1
String=zwei - Wert=2
String=drei - Wert=3
String=vier - Wert=4
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Enum als Bereich für Arrays

Beitrag von Warf »

Enums verhalten sich fast identisch zu Zahlenwerten. Man sollte eigentlich fast nie hin und her konvertieren müssen. For loop iteratoren können vom Typen enum sein. Man kann mittels Intrinsics wie High und Low den Wertebereich eines Enums abgrenzen, man kann mit Succ und Desc (ich glaub sogar auch mit Inc und Dec) das enum navigieren, etc.

Eigentlich gibt es kaum einen Grund das Enum in Zahlen zu konvertieren

Benutzeravatar
Zvoni
Beiträge: 363
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Enum als Bereich für Arrays

Beitrag von Zvoni »

Warf hat geschrieben: Di 1. Apr 2025, 13:30 Eigentlich gibt es kaum einen Grund das Enum in Zahlen zu konvertieren
Der einzige mir bekannte Grund ein Enum in seine String-Repräsentation umzuwandeln ist Logging (und dazu gabs schon mal nen Thread hier).
Ein Enum in seinen Zahlenwert umzuwandeln wäre mir gar kein Grund bekannt.
Zumal das ganze Zeuch mit TypInfo nur für "ununterbrochene" Enums funktioniert (Glaube zumindest, das mal gelesen zu haben)
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

jammernich
Beiträge: 25
Registriert: Di 5. Nov 2024, 22:36
OS, Lazarus, FPC: Win11, Lazarus 3.8
CPU-Target: x86_64bit

Re: Enum als Bereich für Arrays

Beitrag von jammernich »

In dem beschriebenen Fall ist der erste Index automatisch 0 und die weiteren Index-Werte sind fortlaufend. Das stimmt schon, es macht eigentlich keinen Sinn in eine Zahl umzuwandeln.
:? :idea:
Danke Euch für die ausführlichen Antworten!

Manchmal ist Informatik schwer begreifbar :mrgreen:

Mathias
Beiträge: 6899
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Enum als Bereich für Arrays

Beitrag von Mathias »

Ein Enum in seinen Zahlenwert umzuwandeln wäre mir gar kein Grund bekannt.
Mir leider schon.
Bei der Unit GST welche bei FPC dabei ist, muss man enums in interger umwandeln, dann mit or verknüpfen und anschliessend wieder in den enum zurück chasten. So ziemlich das idiotischste das ich kenne.
Das sieht dann so aus:

Code: Alles auswählen

  gst_element_seek_simple(pipelineElement.pipeline, GST_FORMAT_TIME, TGstSeekFlags(int64(GST_SEEK_FLAG_FLUSH) or int64(GST_SEEK_FLAG_KEY_UNIT)), AValue * G_USEC_PER_SEC); 
Daher wandle ich C enums immer in const um, wen ich eine C-Bindung mache.

Ein anderes Beispiel, wen man einen Enum einem userdata von einem callproc übergeben will, muss man auch chasten.
Un dies sogar doppelt, vom enum in einen Integer und dann zu einem Pointer.

Dies alles ist recht unschön,
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Enum als Bereich für Arrays

Beitrag von Warf »

Ja stimmt wenn man mit C Code interagiert ist das Problem das C keine Enum Typen kennt, enums sind einfach nur Integer Konstanten.

Aber was möglich ist ist mit Set Operationen zu arbeiten. Wenn du ein enum Set anlegst und da alle Werte reinschreibst und das dann zu Integer castest bekommst du ein Bitset wie wenn du in C bitkonstanten mit Or verknüpfst

Mathias
Beiträge: 6899
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Enum als Bereich für Arrays

Beitrag von Mathias »

Aber was möglich ist ist mit Set Operationen zu arbeiten. Wenn du ein enum Set anlegst und da alle Werte reinschreibst und das dann zu Integer castest bekommst du ein Bitset wie wenn du in C bitkonstanten mit Or verknüpfst
Ist dies nicht auch wieder ein geflicke ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Enum als Bereich für Arrays

Beitrag von Warf »

Nö ist eigentlich ganz einfach:

Code: Alles auswählen

type
  TFilePermission = (fpRead, fpWrite, fpExecute);
  TFilePermissions = set of TFilePermission;

const
  fpReadWrite = [fpRead, fpWrite];

// C Style
const
  cRead = 1;
  cWrite = 2;
  cExecute = 4;
  cReadWrite = 3;

var
  p1: TFilePermissions;
  p2: Integer;
begin
  p1 := [fpRead, fpExecute];
  p2 := cRead Or cExecute;
  Writeln('Pascal Set: ', Integer(p1)); // 5
  Writeln('C Enum: ', p2); // 5
end.
Ich bin leider grade unter Windows und habe hier keinen C compiler (und linker) daher kann ich das nicht ausprobieren, aber ich würde vermuten das wenn man die folgende C funktion hat:

Code: Alles auswählen

void myFunc(int permissions) { ... }
Die folgende Pascal definition dagegen linken kann:

Code: Alles auswählen

procedure myFunc(permissions: TFilePermissions); cdecl; external;
Bin mir aber nicht zu 100% Sicher, da es sein kann das Pascal die größe für das Set anders wählt, daher ist ein Cast immer die beste option

Antworten