Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Problem beim Übersetzen von C++ nach Delphi


Edmund Jenner-Braunschmie - Mi 27.12.06 18:09
Titel: Problem beim Übersetzen von C++ nach Delphi
Hallo,

ich bin gerade dabei, einen C++ Code ins Delphi zu übersetzen. Es werden Funktionen
einer DLL-Datei implementiert (Ansteuerung einer USB-Kamera).

Nun mein Problem: Wie übersetze ich die Variablen-Deklaration


Quelltext
1:
  typedef void* VRmUsbCamDevice;                    


nach Delphi?

Vielen Dank vorab und wenn ich was genauer beschreiben soll - bitte posten.

lg edi

Hier ein kurzer Ausschnitt aus der C++ Datei:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
// ------------------------------------------------------------------------
// Device Management
// ------------------------------------------------------------------------

typedef void* VRmUsbCamDevice;

typedef struct _VRmDeviceKey
{
  VRmDWORD m_serial;
  const char* mp_manufacturer_str;
  const char* mp_product_str;
  VRmBOOL m_busy;
  void* mp_private;
}VRmDeviceKey;

VRM_API VRmRetVal VRmUsbCamUpdateDeviceKeyList();
VRM_API VRmRetVal VRmUsbCamGetDeviceKeyListSize(VRmDWORD* fp_size);
VRM_API VRmRetVal VRmUsbCamGetDeviceKeyListEntry(VRmDWORD f_index,VRmDeviceKey** fpp_device_key);
VRM_API VRmRetVal VRmUsbCamGetVendorId(const VRmDeviceKey* fp_device_key,VRmWORD* fp_vendor_id);
VRM_API VRmRetVal VRmUsbCamGetProductId(const VRmDeviceKey* fp_device_key,VRmWORD* fp_product_id);
VRM_API VRmRetVal VRmUsbCamFreeDeviceKey(VRmDeviceKey** fpp_device_key);
VRM_API VRmRetVal VRmUsbCamOpenDevice(const VRmDeviceKey* fp_device_key,VRmUsbCamDevice* fp_device);
VRM_API VRmRetVal VRmUsbCamGetDeviceKey(VRmUsbCamDevice f_device,VRmDeviceKey** fpp_device_key);
VRM_API VRmRetVal VRmUsbCamCloseDevice(VRmUsbCamDevice f_device);


Moderiert von user profile iconTino: Code-Tags hinzugefügt.


tommie-lie - Mi 27.12.06 18:39
Titel: Re: Problem beim Übersetzen von C++ nach Delphi
Leute, die Edmund heißen, sind mir zwar normalerweise sehr suspekt, aber ich will mal eine Ausnahme machen, weil's offensichtlich nicht der Stoiber-Edmund ist :mrgreen:

user profile iconEdmund Jenner-Braunschmie hat folgendes geschrieben:
Wie übersetze ich die Variablen-Deklaration

Quelltext
1:
typedef void* VRmUsbCamDevice;                    
nach Delphi?
Das ist keine Variablendeklaration, das ist eine Typendefinition, wie man am typedef erkennen kann. Das Delphi-Äquivalent wäre

Delphi-Quelltext
1:
2:
type
  VRmUsbCamDevice = Pointer;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
type
  VRmUsbCamDevice = Pointer;

type
  VRmDeviceKey = _VRmDeviceKey;
  _VRmDeviceKey = packed record
    m_serial: VRmDword;
    mp_manufacturer_str: PChar;
    mp_product_str: PChar;
    mp_private: Pointer;
  end;


function VRmUsbCamUpdateDeviceKeyList(): VRmRetVal;
function VRmUsbCamGetDeviceKeyListSize(fp_size: PVRmDWORD): VRmRetVal; // es empfiehlt sich, PVRmDWORD als Zeiger auf VRmDWORD zu definieren

// und so weiter

Allerdings fehlen womöglich Aufrufkonventionen. Die stehen wahrscheinlich im Makro VRM_API, dessen Definition du nicht gepostet hast. Unter Umständen muss bei den Funktionsdeklarationen also noch mit stdcall oder cdecl hantiert werden.


Edmund Jenner-Braunschmie - Do 28.12.06 11:00

@ Thomas:
vorerst Danke, dass Du meinen offensichtlich vorbelasteten Vornamen akzeptierst :D.
Jedenfalls hast Du mir sehr geholfen. Mein Fehler war, dass ich stdcall statt
cdecl verwendet habe. Jetzt funktioniert's soweit - auskennen, was stdcall oder cdecl für'n
Unterschied macht, tu ich mich jedoch nicht - ist aber jetzt nicht so wichtig. Höchstens es
freut jemanden dies zu erklären - interessant wär's schon ;). - sonst kann ich mich
diesbezüglich irgendwann mal im Forum umsehen.

Wichtiger für mich ist nun eine Lösung für das nächste Problem bei der Übersetzung von
C++ nach Delphi!

nochwas: den Unterschied zwischen Typdefinition und Variablendeklaration kenne ich schon -
das war vorhin ein Versprecher - peinlich, peinlich :oops: !!

lg edi

Hier der C++ Code (was bedeutet das =1<<0 usw.?):


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
/// enum for image modifiers
typedef enum _VRmImageModifier
{
  /// standard image, top->down, left->right orientation
  VRM_STANDARD=0,
  /// vertical mirrored
  VRM_VERTICAL_MIRRORED=1<<0,
  /// horizontal mirrored
  VRM_HORIZONTAL_MIRRORED=1<<1,
  /// first field of interlaced image
  VRM_INTERLACED_FIELD0=1<<2,
  /// second field of interlaced image
  VRM_INTERLACED_FIELD1=1<<3,
  /// any field of interlaced image (this is only used for format selection)
  VRM_INTERLACED_FIELD01=1<<4,
  /// both fields of interlaced image
  /// upper half image is the first field, lower half image is the second field
  VRM_INTERLACED_FRAME=1<<5,
  /// internal modifier, can be ignored
  VRM_CORRECTION_LUT_1CHANNEL_8=1<<6,
  /// internal modifier, can be ignored
  VRM_CORRECTION_LUT_1CHANNEL_10=1<<7,
  /// internal modifier, can be ignored
  VRM_CORRECTION_LUT_4CHANNEL_8=1<<8,
  /// internal modifier, can be ignored
  VRM_CORRECTION_LUT_4CHANNEL_10=1<<9,
  /// this format has a changeable ROI (User ROI)
  VRM_USER_ROI=1<<10,
  /// subsampled image (skipped pixels or binning)
  VRM_SUBSAMPLED=1<<11
}VRmImageModifier;


Moderiert von user profile iconraziel: C#-Tags hinzugefügt


wulfskin - Do 28.12.06 11:20

Hallo Edi,

<< ist der left-shift Operator, also äquivalent zu shl. Mehr dazu hier: http://www.cprogramming.com/tutorial/bitwise_operators.html.

Gruß Hape!


tommie-lie - Do 28.12.06 11:56

user profile iconEdmund Jenner-Braunschmie hat folgendes geschrieben:
Mein Fehler war, dass ich stdcall statt cdecl verwendet habe. Jetzt funktioniert's soweit - auskennen, was stdcall oder cdecl für'n Unterschied macht, tu ich mich jedoch nicht
Die IA32 (x86-Prozessoren und kompatible) bietet natürlich von sich aus keine Methode, an Funktionsaufrufe mit Parametern zu versehen. Das nötige Mnemonic in Assembler ist CALL und nimmt als Parameter lediglich die Zieladresse der aufzurufenden Funktion an, keine zusätzlichen Funktionsparameter. Also muss man sich irgendwie darauf einigen, wie Parameter übergeben werden sollen, denn da gibt es diverse Möglichkeiten. Man könnte sie zum einen von rechts nach links auf den Stack schieben und es der aufgerufenen Funktion überlassen, sie wieder von dort runtezuholen (stdcall). Oder man könnte es genauso machen, aber derjenige, der die Funktion aufruft, muss den Stack wieder aufräumen (cdecl). Oder man könnte vereinbaren, daß einige Register des Prozessors die Parameter enthalten sollen und erst, wenn mehr Parameter benötigt werden, als Register vorhanden sind, wird der Stack verwendet (FastCall). Das alles nennt man Aufrufkonventionen, und wenn ein Compiler mehrere Aufrufkonventionen verwendet, muss man ihm mitteilen, welche er verwenden soll. In der Win32-API ist es üblich, stdcall zu verwenden, also ausschließlich den Stack für Parameterübergaben zu benutzen. Ein C-Compiler ohne Optimierung verwendet normalerweise cdecl als Aufrufkonvention.

Den Shift-Left-Operator hat Hape ja schon erklärt, eine andere gute C(++)-Referenz ist http://cppreference.com/. Dort kannst du neben den Operatoren auch die unterschiedlichen Schlüsselwörter, Wertebereiche von Datentypen oder Standardfunktionen der Standard C Library oder der STL nachschlagen.


Edmund Jenner-Braunschmie - Do 28.12.06 16:00

Hi,

wiedermal Danke für alle Antworten.

Das mit SHL habe ich verstanden, das mit den Aurfufkonventionen glaube ich auch verstanden zu haben.


Quelltext
1:
2:
3:
1<<0 = 1;
1<<1 = 2;
1<<2 = 4;

... ist also nur eine andere Schreibweise?! Soweit hab ich's dann verstanden - hoffe es passt.

Jetzt aber noch was Grundlegendes:

Diese Typdefinition


Quelltext
1:
typedef enum _VRmImageModifier { VRM_STANDARD=0,VRM_VERTICAL_MIRRORED=1<<0, ..... }                    


entspricht ja in Delphi etwa:


Delphi-Quelltext
1:
2:
type
  _VRmImageModifier = (VRM_STANDARD, VRM_VERTICAL_MIRRORED, .... )


?? oder liege ich falsch?? Aber was mache ich in delphi dann mit =0, =1,... ??

Also irgendwas habe ich da noch nicht richtig "drauf"!!

Bitte um Hilfe

Moderiert von user profile iconraziel: Delphi-Tags hinzugefügt


Delete - Do 28.12.06 16:04

Wegen der Aufrufkonventionen: http://www.michael-puff.de/Developer/Artikel/2006_03/Aufrufkonventionen.shtml


wulfskin - Do 28.12.06 16:18

Hallo,

ich weiss leider nicht wie Delphi intern die Menge Set of bearbeitet, aber vielleicht wäre das genau das passende.
Auf jeden Fall geht das aber ohne Menge und zwar so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
(*
typedef enum _VRmImageModifier
{
/// standard image, top->down, left->right orientation
VRM_STANDARD=0,
/// vertical mirrored
VRM_VERTICAL_MIRRORED=1<<0,
*)


type
  VRM_STANDARD = 0;
  VRM_VERTICAL_MIRRORED = 1;
  {usw...}

//Der Aufruf mehrer erfolgt dann so, wenn du beides haben möchtest...
  Func(VRM_STANDARD or VRM_VERTICAL_MIRRORED);

//Wenn du was prüfen möchtest...
  if (Var and VRM_STANDARD) > 0 then {..};
Das ist übrigens auch typisch für API-Befehl, die werden auch so übersetzt.

Viele Grüße,
Hape


wulfskin - Do 28.12.06 16:24

Nachtrag:

Hab gerade auch noch mal ganz kurz im Internet geforscht, weil es mich jetzt auch interessiert.
in diesem Delphikurs [http://www.epinasoft.com/delphikurs/dkk_sets.html] hab ich folgendes gefunden:
Zitat:
[...] Sets können in Pascal maximal 256 Elemente umfassen und sind sehr effizient implementiert. Umfasst ein Set weniger als 32 Basiselemente, so versucht der Compiler das Set in einem Register der CPU zu halten, wodurch der Zugriff auf Sets und deren Bearbeitung extrem schnell wird.
Das spricht doch stark dafür, dass Menge intern auch als 2er-Potenzen abgespeichert werden, würde ja auch Sinn.

Kurzum, folgendes sollte dann also auch funktionieren:

Delphi-Quelltext
1:
2:
3:
type
  TVRmImageModifier = (VRM_STANDARD, VRM_VERTICAL_MIRRORED {...});
  TVRmImageModifiers = set of TVRmImageModifier;
Gruß Hape!


tommie-lie - Do 28.12.06 18:13

Damit verlässt man sich aber auf eine bestimmte Implementierung des Compilers. Solange das im Sprachstandard nicht definiert ist, würde ich nicht davon ausgehen, daß sich in Zukunft das Verhalten des DCC nicht ändern wird oder daß ein anderer Compiler (FreePascal, GNU Pascal) das genauso machen.

user profile iconEdmund Jenner-Braunschmie hat folgendes geschrieben:
Aber was mache ich in delphi dann mit =0, =1,... ??
Damit kannst du bei einem selbstdefinierten Enumerationstyp (das, was du mit type blubb = (EINS, ZWEI, DREI); machst) genau festlegen, welche Werte die einzelnen Elemente haben sollen. In Pascal sind ja die Enumerationselemente alle wie globale Konstanten benutzbar, und so kannst du ihnen bestimmte Werte zuweisen. Tust du das nicht, vergibt der Compiler Standardwerte.


BenBE - Mo 08.01.07 22:56

user profile iconEdmund Jenner-Braunschmie hat folgendes geschrieben:
Diese Typdefinition

typedef enum _VRmImageModifier { VRM_STANDARD=0,VRM_VERTICAL_MIRRORED=1<<0, ..... }

entspricht ja in Delphi etwa:


Delphi-Quelltext
1:
2:
type
  _VRmImageModifier = (VRM_STANDARD, VRM_VERTICAL_MIRRORED, .... );


?? oder liege ich falsch?? Aber was mache ich in delphi dann mit =0, =1,... ??

In Delphi kannst Du dieser Werte problemlos übernehmen ;-) Das machen Enums mit ...

Normalerweise übersetzt man solche vorinitialisierten Enums aus C++ in Delphi jedoch einfach als Konstanten-Listen, da sie in C++ nix anderes sind.



Delphi-Quelltext
1:
2:
3:
4:
5:
type
  _VRmImageModifier = (
    VRM_STANDARD = 1 shl 0
    VRM_VERTICAL_MIRRORED = 1 shl 1
    {....} );


Aber wie gesagt: Häufiger findet man in Delphi folgende Übersetzung:

Delphi-Quelltext
1:
2:
3:
4:
const
    VRM_STANDARD = 1 shl 0;
    VRM_VERTICAL_MIRRORED = 1 shl 1;
    {....}