C/C++ zu PB: Reference, Dereference, Pointer, By Reference?

Fragen zu allen anderen Programmiersprachen.
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

C/C++ zu PB: Reference, Dereference, Pointer, By Reference?

Beitrag von Regenduft »

Hallöle beieinander,

es geht wie in meinem letzten Posting in diesem Forum immer noch um die Portierung von "DrPetter's sfxr" von C nach PureBasic. Ich hatte vor fast 7 Jahren die C-Grundlagen gelernt und nur etwa ein Jahr lang aktiv damit gearbeitet und bin dem entsprechend ziemlich unsicher...

Ich würde mich sehr freuen, wenn jemand auf die folgenden Übersetzungen mal einen Blick werfen könnte, ob ich das richtig umgesetzt habe! (Es handelt sich nur um auf die Grundlagen heruntergebrochenen sinnlosen Code; x64-Kompatibilität wurde vernachlässigt)
  1. Übersetzung von C nach PB

    Code: Alles auswählen

    int a, b;
    a = b;
    a = &b;
    a = *b;
    

    Code: Alles auswählen

    Define.l a, b
    a = b
    a = @b
    a = PeekL(b) ; oder PeekB(b) ?
  2. Übersetzung von C nach PB

    Code: Alles auswählen

    int *a, *b;
    a = b;
    a = *b;
    a = &b;

    Code: Alles auswählen

    Define.Long *a, *b
    *a =  *b
    *a =  *b\l
    *a = @*b
  3. Übersetzung von C nach PB

    Code: Alles auswählen

    int y;
    
    void foo(int& x)
    {
      x = 123
    }
    
    void main(void)
    {
      foo(y)
    }

    Code: Alles auswählen

    Define.l y
    
    Procedure foo(*x.Long)
      *x\l = 123
    EndProcedure
    
    foo(@y)
  4. Übersetzung von C nach PB

    Code: Alles auswählen

    int y;
    
    void foo(int* x)
    {
      x = 123
    }
    
    void main(void)
    {
      foo(y)
    }

    Code: Alles auswählen

    Define.l y
    
    Procedure foo(*x.Long)
      *x = 123
    EndProcedure
    
    foo(y)
[offtopic]

Wenn ich mir die Codes so ansehe fällt mir wieder ein, warum ich bei PB hängengeblieben bin:
  • Im Verhältnis zu C braucht man zwar "mehr Buchstaben pro Zeile", hat aber eine viel schönere/übersichtichere Syntax, weniger "mehrfach belegte Sonderzeichen" und kann ähnlich low level arbeiten (im Notfall per ASM)
  • Im Verhältnis zu VB hat man zwar deutlich mehr Schreibaufwand, allerdings auch deutlich kleinere "runtime-dll-freie" und zumeist effizientere Executeables. Außerdem WENN einmal bei VB etwas nicht so funktioniert wie man will, dann kann man sich Ewigkeiten damit abmühen zu suchen, wo VB heimlich "etwas verbiegt".
    Kleine Anekdote: In meiner Reha vor ein paar Monaten hatte ich im zwei Mann Team versucht per RS232 ein Programm in Ascii-Hex-Format an ein µController-Board zu übertragen. Es war ein unglaublicher Aufwand, da VB einfach kreuz und quer die zu sendenden Daten herumkonvertiert hatte! Da Unicode-Strings Probleme machten und wir nicht wussten wie man in VB nach Ascii konvertiert hatten wir es per Übertragung einzelner Roh-Bytes versucht (die Sende-Methode hat ja gefühlte 1000 Überladungen). Allerdings kam dann auch hier zunächst nur Quatsch an, da VB heimlich die Byte-Werte in Strings wandelte (wie mit Str()) und dann den Ascii-Wert des ersten Buchstabens sendete (also z.B. 53 bei Asc("9"), weil Asc("9") = 57 und Chr(Left(Str(57),1)) = 53)! :freak:
[/offtopic]
Zuletzt geändert von Regenduft am 18.10.2013 03:48, insgesamt 2-mal geändert.
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von ts-soft »

int = Long in PB! (nicht Integer)
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von Regenduft »

ts-soft hat geschrieben:int = Long in PB! (nicht Integer)
Danke! Den Fehler mache ich auch immer mit char und Character statt Ascii...

Sonst alles korrekt?! Das würde mich ja umhauen! :o
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von Danilo »

Regenduft hat geschrieben:Sonst alles korrekt?! Das würde mich ja umhauen! :o
Nein, aber der C-Code ist halt kein korrekter C-Code sondern nur Pseudo-Code.

Beispiel:

Code: Alles auswählen

int a, b;
a = *b;
darf in C nicht kompilieren, da "int" und "Pointer zu int" inkompatible Typen sind.
Auch ist der Pointer '*b' im ersten Abschnitt im C-Code nicht deklariert, nur ein "int b".
Für korrekten, lauffähigen Code wäre ein Typ-Cast von "Pointer zu int" zu "int" notwendig,
was auf 64bit Windows aber falsch wäre, da ein 64bit-Pointer nicht in ein 32bit "int" konvertiert
werden kann.

Wenn der C-Code schon nicht richtig ist, fällt es etwas schwer den übersetzten PB-Code
zu bewerten, bzw. kann man das dann nicht in Richtig oder Falsch einteilen, wenn der
C-Code schon nicht lauffähig ist.

Die Speichergröße von "int" hängt bei C übrigens von der Platform und vom Compiler ab.
Auf Windows x86 + x64 ist ein "int" 32bit lang, also in PB ein Long. Auf anderen Plattformen
kann ein C "int" aber etwas Anderes sein.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von Regenduft »

Danke Danilo!
Danilo hat geschrieben:Beispiel:

Code: Alles auswählen

int a, b;
a = *b;
darf in C nicht kompilieren (...).
Für korrekten, lauffähigen Code wäre ein Typ-Cast von "Pointer zu int" zu "int" notwendig,
was auf 64bit Windows aber falsch wäre (...).
Mal den 64-Bit Fall vernachlässigt; So wäre dann richtig, oder? :

Code: Alles auswählen

int a, b;
a = (int)*b;
Danilo hat geschrieben:Wenn der C-Code schon nicht richtig ist, fällt es etwas schwer den übersetzten PB-Code zu bewerten (...).
Ja, wollte nicht den kompletten teils ziemlich wirren Originalcode posten (und die Hilfsbereitschaft überstrapazieren) und habe wohl beim runterkürzen auch in C Fehler eingebaut... Bin eindeutig von PureBasic zu Autocast verwöhnt für C. :wink:
Danilo hat geschrieben:Die Speichergröße von "int" hängt bei C übrigens von der Platform und vom Compiler ab.
Der Original-Code ist für x86 Windows und Linux. Ich werde erst mal x86 beibehalten und wenn es soweit lauffähig ist (also korrekt übersetzt) auf x86/x64 aufbohren. Ist ja einfach mit PureBasic.

Falls es nicht so ganz rüber kam: Ich wollte einfach Sicherheit gewinnen, ob ich das mit Reference, Dereference und Pointer in C richtig verstanden habe (besonders als Funktionsparameter). Was mir ziemliche Kopfschmerzen macht ist "int& variable" als Functionsparameter (by Reference?). Wenn jemand Lust hat das mal in Prosa oder per Beispiel-Code zusammenzufassen würde ich mich auch tierisch freuen! Fand es aber faul einfach direkt nach so etwas zu bitten...

Ich werde später den Code aus dem Startposting korrigieren! (Gerade keine Zeit und unsicher ob meine Korrektur richtig ist)
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von Danilo »

Regenduft hat geschrieben:Was mir ziemliche Kopfschmerzen macht ist "int& variable" als Functionsparameter (by Reference?).
Das ist by Reference in C++. C unterstützt das gar nicht.

Zu den Pointern, die werden mit Sternchen deklariert.
Zugriff auf das Element, auf das der Zeiger zeigt, gibt es dann mit Sternchen.
Ohne Sternchen Zugriff auf den Zeigerwert selbst.
Ist also anders als PB, wo man Pointer immer mit Sternchen schreibt
und immer über '\' auf das Element zugreift.

Das heisst wenn der int-pointer *b einen korrekten Wert hat, dann ist
int a = *b schon richtig. Den Pointer-Wert sprichst Du mit 'b' an, also
ohne Sternchen.

Code: Alles auswählen

#include <stdio.h>

int main(int argc, char *argv[])
{
    int a, *b; // "int a" und "pointer to int b"

    b = &a;    // pointer b setzen, er bekommt die adresse von a

    *b = 123;  // in die speicherstelle schreiben, zu der Zeiger b zeigt

    printf("Wert von a            : %i\n",  a); // a
    printf("Wert von *b           : %i\n", *b); // Speicherzelle auf die der Pointer b zeigt ausgeben
    printf("Wert von Pointer b    : %P\n",  b); // den Pointer ausgeben (Adresse von a)
    printf("Adresse von Variable a: %P\n", &a); // Adresse von a ausgeben

    return 0;
}

/* Ausgabe:

Wert von a            : 123
Wert von *b           : 123
Wert von Pointer b    : 0018FF4C
Adresse von Variable a: 0018FF4C

*/
Mit Pelles C oder LCCwin32/64 könntest Du ja lauffähige Codes machen,
die Du dann nach PB übersetzt. Oder Du nimmst C++, dann gibt es auch
die Parameter by Reference.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von auser »

In Beispiel 2 ist jedenfalls ein Fehler drin.

C:

Code: Alles auswählen

int *a, *b;
a = *b;
Hast du in PB übersetzt mit:

Code: Alles auswählen

Define.Long *a, *b
*a\l =  *b\l
In C setzt du die Zieladresse von Pointer a auf den Inhalt den es bei Pointer b über das "*" zu holen gibt (was ziemlich sicher eine Compilerwarnung gibt - aber zumindest mit gcc kompilieren sollte). In PB hingegen setzt du die Inhalte gleich (machst also etwas völlig anderes).

An der Stelle will ich anmerken daß mir das Verhalten von C hier wesentlich besser gefällt. Da darf ich nämlich den Typ auf den der Pointer verweist setzen und lege fest wie er den Inhalt später lesen und schreiben darf. Also brauch ich dann nicht zig verschiedene PeekA, PeekB, PeekC, PeekI, PeekL, usw... und PokeB, PokeC, PokeI, PokeL usw... sondern einfach nur das "*". Und wenn ich irgendwann mal feststelle daß ich statt 1 Byte doch 4 Bytes brauche ändere ich halt den Typ im Header... wohingegen ich in PB dann überall im Program PeekB auf PeekL oder *a\b auf *a\l umschreiben muss. Es stimmt schon daß das "*" in C mehrfach belegt ist. Einmal legt man damit in der Definition (meist im Header) fest daß es ein Pointer ist ... und im Program selbst machst du über das * dann quasi immer automatisch das richtige Peek und Poke um den Inhalt auszulesen oder zu schreiben.

Also wäre in C ein:

Code: Alles auswählen

*a = *b; 
...quasi das in PB (wobei das aber freilich in PB nicht funzt... da musst du angeben welcher Typ das ist).

Code: Alles auswählen

PokeAUTOMATISCH(*a,PeekAUTOMATISCH(*b))

Mfg,
auser
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von auser »

Regenduft hat geschrieben:Was mir ziemliche Kopfschmerzen macht ist "int& variable" als Functionsparameter (by Reference?).
Stell dir das einfach als Vereinfachung für das Problem vor wenn du z.B. eine Funktion basteln willst die mehr als einen Wert zurückgeben soll. In PB oder C wirst du dazu wahrscheinlich Pointer bemühen. In C++ hättest du es einfacher.

Beispiel PB:

Code: Alles auswählen

Procedure plus_eins(*a)  
  PokeI(*a,PeekI(*a) + 1) 
EndProcedure 

Define x.i = 0

plus_eins(@x)
Debug(x) ; 1

plus_eins(@x)
Debug(x) ; 2
Wär's nicht schön wenn dieses ganze gepeeke und poke verschwinden würde und du nicht ein @x brauchst um eine Adresse zu bemühen sondern einfach nur x schreiben kannst? Wäre PB ein bisschen eher wie C++ würde das gehen und dann irgendwie so aussehen (was freilich das aktuelle PB so nicht versteht):

Code: Alles auswählen

; Funzt ned ... 
Procedure plus_eins(@a.i) ; PB versteht das nicht. 
  a = a + 1  
EndProcedure

Define x.i = 0
plus_eins(x) ; geht net 
Also in C++ bräuchtest du beim Aufruf der Prozedur nicht erst die Adresse ergründen sondern du könntest direkt die Variable als Funktionsparameter reinschreiben und in der Prozedur brauchst du auch nicht Pointer Peeken oder Poken... auch keine "*" verwenden sondern du tust innerhalb der Prozedur so als ob es eine normale Variable wäre... nur daß die Variable in dem Fall nicht ein kurzlebiger temporärer Clone ist der nach der Prozedur verschwindet sondern von außerhalb der Prozedur ins Leben gerufen wurde, durch die Prozedur "durchgezogen" wird und auch nach dem Ende der Prozedur noch weiter lebt... mit dem Wert der in der Prozedur gesetzt wurde. Ob im Hintergrund dann eigentlich so ziemlich das selbe geschieht wie du da in PB mit Peek und Poke gemacht hättest braucht dich nicht weiter zu kümmern.


Mfg,
auser
Benutzeravatar
Regenduft
Beiträge: 574
Registriert: 25.03.2008 15:07
Wohnort: THE LÄÄÄND!

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von Regenduft »

Danke nochmal an euch alle drei!

Meine Wissenslücken sind nun soweit geschlossen, dass ich "kritische Stellen" im aktuellen Projekt prüfen und korrigieren kann! Habe sogar noch etwas darüber hinaus gelernt.

Das einzige was mir noch nicht ganz klar ist, ist dass ich zwar mehrfach gelesen habe, dass "Pointer-Sternchen" und "Dereferrer-Operator-Sternchen" zwei total unterschiedliche Dinge sind und dass man die nur nicht durcheinander bringen soll. Aber WAS der Unterschied sein soll konnte ich nicht erkennen... oder ist da einfach nur zum einen das Sternchen bei der Zeigerdeklaration und zum anderen das Sternchen im Code (z.B. bei einer Zuweisung) gemeint? Wenn ja, dann hätte ich's doch verstanden... :?
Danilo hat geschrieben:Das ist by Reference in C++. C unterstützt das gar nicht.
Gut zu wissen! Ja, das Original sfxr ist in eigentlich C++, allerdings hatte ich nur C-Code ausmachen können. In C++ kann ich nicht programmieren, sonder nur (manchmal mit einiger Mühe) Code-Beispiele nachvollziehen, wie Sie hier im Board ja auch ab und zu mal verlinkt werden.
Danilo hat geschrieben:Mit Pelles C oder LCCwin32/64 könntest Du ja lauffähige Codes machen,
die Du dann nach PB übersetzt. Oder Du nimmst C++, dann gibt es auch
die Parameter by Reference.
Ich habe Visual-Studio Express 2012 installiert (eigentlich nur um einen Pacman-Klon in VB fertig zu schreiben, welchen ich während meiner bereits erwähnten Reha begann). Übrigens, falls es nicht rüberkam, mein Projekt ist eine Portierung von C(++) nach PureBasic; vielleicht bezogst Du Dich aber ja auch nur auf das Kompilieren Deines Beispiel-Codes.
auser hat geschrieben:In Beispiel 2 ist jedenfalls ein Fehler drin.
Oh! Danke, hab's korrigiert!
auser hat geschrieben:Stell dir das (by Reference) einfach als Vereinfachung für das Problem vor wenn du z.B. eine Funktion basteln willst die mehr als einen Wert zurückgeben soll. In PB oder C wirst du dazu wahrscheinlich Pointer bemühen. In C++ hättest du es einfacher.
(...)
Wär's nicht schön wenn dieses ganze gepeeke und poke verschwinden würde und du nicht ein @x brauchst um eine Adresse zu bemühen sondern einfach nur x schreiben kannst? Wäre PB ein bisschen eher wie C++ würde das gehen und dann irgendwie so aussehen (was freilich das aktuelle PB so nicht versteht):

Code: Alles auswählen

; Funzt ned ... 
Procedure plus_eins(@a.i) ; PB versteht das nicht. 
  a = a + 1  
EndProcedure

Define x.i = 0
plus_eins(x) ; geht net
Naja... geht doch fast so... Allerdings wäre ein richtiges ByRef schon schön! Besonders für Strings, da es dort ja keine Lösung gibt. Auch nicht mit Zeigern und/oder gepiekste und gestupse.

Code: Alles auswählen

; Funzt...
Procedure plus_eins(*a.Integer) ; PB versteht das.
  *a\i + 1
EndProcedure

Define x.i = 0
plus_eins(@x) ; geht
auser hat geschrieben:An der Stelle will ich anmerken daß mir das Verhalten von C hier wesentlich besser gefällt. Da darf ich nämlich den Typ auf den der Pointer verweist setzen und lege fest wie er den Inhalt später lesen und schreiben darf. Also brauch ich dann nicht zig verschiedene PeekA, PeekB, PeekC, PeekI, PeekL, usw... und PokeB, PokeC, PokeI, PokeL usw... sondern einfach nur das "*".
Ich nutze lieber strukturierte Zeiger. Peeks und Pokes verwende ich eigentlich nur zum Debuggen oder wenn ich eine Demo-Code poste und davon ausgehe, dass das Gegenüber Anfänger ist und noch nicht mit Zeigern umgehen kann. Zeiger sind einfach schneller und übersichtlicher.
auser hat geschrieben:Und wenn ich irgendwann mal feststelle daß ich statt 1 Byte doch 4 Bytes brauche ändere ich halt den Typ im Header... wohingegen ich in PB dann überall im Program PeekB auf PeekL oder *a\b auf *a\l umschreiben muss.
Ich finde es zwar generell gut, dass man bei PureBasic (anders als bei C) standardmäßig im Code immer sofort erkennen kann, auf was für einen Typ der Zeiger verweißt, allerdings gibt's in PureBasic da einen ganz einfachen Trick, damit man genauso einfach wie in C den Typ nachträglich einfach im Header ändern kann! Hier mal mein Standard-Strukturen-Template:

Code: Alles auswählen

DeclareModule pbex_Structure
  ; anonyme Standardtypen
  Structure AsciiN     : n.a : EndStructure
  Structure ByteN      : n.b : EndStructure
  Structure CharacterN : n.c : EndStructure
  Structure DoubleN    : n.d : EndStructure
  Structure FloatN     : n.f : EndStructure
  Structure IntegerN   : n.i : EndStructure
  Structure LongN      : n.l : EndStructure
  Structure QuadN      : n.q : EndStructure
  Structure UnicodeN   : n.u : EndStructure
  Structure WordN      : n.w : EndStructure
  ; offene Standard-Arraytypen
  Structure AsciiArray     : a.a[0] : EndStructure
  Structure ByteArray      : b.b[0] : EndStructure
  Structure CharacterArray : c.c[0] : EndStructure
  Structure DoubleArray    : d.d[0] : EndStructure
  Structure FloatArray     : f.f[0] : EndStructure
  Structure IntegerArray   : i.i[0] : EndStructure
  Structure LongArray      : l.l[0] : EndStructure
  Structure QuadArray      : q.q[0] : EndStructure
  Structure UnicodeArray   : u.u[0] : EndStructure
  Structure WordArray      : w.w[0] : EndStructure
  ; anonyme offene Standard-Arraytypen
  Structure AsciiArrayN     : n.a[0] : EndStructure
  Structure ByteArrayN      : n.b[0] : EndStructure
  Structure CharacterArrayN : n.c[0] : EndStructure
  Structure DoubleArrayN    : n.d[0] : EndStructure
  Structure FloatArrayN     : n.f[0] : EndStructure
  Structure IntegerArrayN   : n.i[0] : EndStructure
  Structure LongArrayN      : n.l[0] : EndStructure
  Structure QuadArrayN      : n.q[0] : EndStructure
  Structure UnicodeArrayN   : n.u[0] : EndStructure
  Structure WordArrayN      : n.w[0] : EndStructure
  ; String- und String-Arraytypen
  Structure FixString       : s.s{1}    : EndStructure
  Structure FixStringArray  : s.s{1}[0] : EndStructure
  Structure FixString2      : StructureUnion : s.s{1}    : c.c    : EndStructureUnion : EndStructure
  Structure FixStringArray2 : StructureUnion : s.s{1}[0] : c.c[0] : EndStructureUnion : EndStructure
EndDeclareModule
Module        pbex_Structure
  ; blind
EndModule
Bei Peek/Poke gestaltet sich das ganze natürlich etwas aufwendiger... Ich habe da mal ein wiederverwendbares Template geschrieben, mit dem das geht. Es bietet den Vorteil gegenüber Zeigern, dass die Größe des zu lesenden Typs dynamisch zur Laufzeit geändert werden kann. Da ich Prototypes verwende ist das ganze auch relativ flott.

Ich habe mal geschwind den recht alten Code als Modul umgeschrieben (ich liebe die neuen Module!). Es ist also Vorsicht geboten! Es ist gut möglich, dass ich beim Umschreiben Fehler eingebaut habe. Ausgiebig getestet habe ich den Code noch nicht! Der Code enthält übrigens einige Redundanzen um ein fortlaufendes Schema zu garantieren (eigentlich war das ganze sowieso eher ein Machbarkeitsversuch).

Da der Code "ein ziemlicher Brocken" ist hier erstmal eine Kurzanleitung:
  • Die ganzen "pbex_Memory_P..." Untermodule sind in "pbex_Memory" zusammengefasst, damit man einfach dort Funktionen auskommentieren kann und nur einen UseModule-Aufruf benötigt;
  • Wo ich Makros nutze habe ich bei Zeigern das "*" durch ein "p" ersetzt (z.B. "pQuelle" statt "*Quelle");
  • PeekValI() und PokeValI() sind für Integerwerte (alle in PB vorhandenen Typen);
  • PeekValF() und PokeValF() für Gleitkommawerte (Float und Double);
  • PeekVal() arbeitet statt mit einem Rückgabewert mit 2 Zeigern (1 Eingabe, 1 Ausgabe) und funktioniert mit allen Datentypen (Integer und Gleitkomma);
  • Um den zu lesenden oder zu schreibenden Datentyp zu ändern ist jeder Peek- und Poke-Funktion eine Set...Type() Funktion zugeordnet. Zum ermitteln des aktuellen Datentypes gibt es ein Get-Pendant.
  • Alternativ zu vorigem gibt es noch je eine Peek...Step() und Poke...Step() Funktion um die Schrittweite in Byte zu ermitteln (zum einfachen Zeiger inkrementieren).
  • EDIT: Zu Beginn sind alle Prototypes auf eine Dummy-Prozedur gesetzt und Datentyp- wie Step-Prozeduren geben #False rück, damit ein IMA unwahrscheinlicher wird. Als erstes also den Datentyp festlegen! Sonst machen die Peek und Poke funktionen schlichweg überhaupt gar nichts!

Code: Alles auswählen

DeclareModule pbex_Memory_PeekVal
  Prototype PeekVal(*Source, *Destination) : Global PeekVal.PeekVal
  Declare.i PeekValStep(GetDestinationStep)
  Declare.i GetPeekValType(GetDestinationType)
  Declare.i SetPeekValType(SourceDataType, DestinationDataType)
EndDeclareModule
Module        pbex_Memory_PeekVal
  EnableExplicit
  Macro PKV2(_sb_, _db_, _st_, _dt_)
    Procedure PeekVal_#_sb_#_db_(*Source._st_, *Destination._dt_)
      *Destination\_db_ = *Source\_sb_
    EndProcedure
  EndMacro
  Macro PKV(_sb_, _st_)
    PKV2(_sb_, A, _st_, Ascii)
    PKV2(_sb_, B, _st_, Byte)
    PKV2(_sb_, C, _st_, Character)
    PKV2(_sb_, I, _st_, Integer)
    PKV2(_sb_, L, _st_, Long)
    PKV2(_sb_, Q, _st_, Quad)
    PKV2(_sb_, U, _st_, Unicode)
    PKV2(_sb_, W, _st_, Word)
  EndMacro
  Macro SPVT_Case2(_sb_, _db_, _st_, _dt_)
    Case #PB_#_st_ | #PB_#_dt_ << 16
      PeekValSourceStep = SizeOf(_st_)
      PeekValDestinationStep = SizeOf(_dt_)
      PeekVal = @PeekVal_#_sb_#_db_()
  EndMacro
  Macro SPVT_Case(_sb_, _st_)
    SPVT_Case2(_sb_, A, _st_, Ascii)
    SPVT_Case2(_sb_, B, _st_, Byte)
    SPVT_Case2(_sb_, C, _st_, Character)
    SPVT_Case2(_sb_, I, _st_, Integer)
    SPVT_Case2(_sb_, L, _st_, Long)
    SPVT_Case2(_sb_, Q, _st_, Quad)
    SPVT_Case2(_sb_, U, _st_, Unicode)
    SPVT_Case2(_sb_, W, _st_, Word)
  EndMacro
  PKV(A, Ascii)
  PKV(B, Byte)
  PKV(C, Character)
  PKV(I, Integer)
  PKV(L, Long)
  PKV(Q, Quad)
  PKV(U, Unicode)
  PKV(W, Word)
  Procedure PeekVal_DUMMY(*Source, *Destination) : EndProcedure
  Global PeekValSourceStep, PeekValDestinationStep, PeekValSourceType, PeekValDestinationType
  ; Public
  PeekVal =  @PeekVal_DUMMY()
  Procedure.i PeekValStep(GetDestinationStep)
    If GetDestinationStep = #False
      ProcedureReturn PeekValSourceStep
    Else
      ProcedureReturn PeekValDestinationStep
    EndIf
  EndProcedure
  Procedure.i GetPeekValType(GetDestinationType)
    If GetDestinationType = #False
      ProcedureReturn PeekValSourceType
    Else
      ProcedureReturn PeekValDestinationType
    EndIf
  EndProcedure
  Procedure.i SetPeekValType(SourceDataType, DestinationDataType)
    If SourceDataType      = #PB_Ignore : SourceDataType      = PeekValSourceType      : EndIf
    If DestinationDataType = #PB_Ignore : DestinationDataType = PeekValDestinationType : EndIf
    Select SourceDataType | DestinationDataType << 16
      SPVT_Case(A, Ascii)
      SPVT_Case(B, Byte)
      SPVT_Case(C, Character)
      SPVT_Case(I, Integer)
      SPVT_Case(L, Long)
      SPVT_Case(Q, Quad)
      SPVT_Case(U, Unicode)
      SPVT_Case(W, Word)
      Default : ProcedureReturn #False
    EndSelect
    PeekValSourceType      = SourceDataType
    PeekValDestinationType = DestinationDataType
    ProcedureReturn #True
  EndProcedure
EndModule
DeclareModule pbex_Memory_PeekValI
  Prototype.q PeekValI(*Memory) : Global PeekValI.PeekValI
  Declare  .i PeekValIStep()
  Declare  .i GetPeekValIType()
  Declare  .i SetPeekValIType(DataType)
EndDeclareModule
Module        pbex_Memory_PeekValI
  EnableExplicit
  Procedure.q PeekValI_A(*Memory.Ascii)     : ProcedureReturn *Memory\a : EndProcedure
  Procedure.q PeekValI_B(*Memory.Byte)      : ProcedureReturn *Memory\b : EndProcedure
  Procedure.q PeekValI_C(*Memory.Character) : ProcedureReturn *Memory\c : EndProcedure
  Procedure.q PeekValI_I(*Memory.Integer)   : ProcedureReturn *Memory\i : EndProcedure
  Procedure.q PeekValI_L(*Memory.Long)      : ProcedureReturn *Memory\l : EndProcedure
  Procedure.q PeekValI_Q(*Memory.Quad)      : ProcedureReturn *Memory\q : EndProcedure
  Procedure.q PeekValI_U(*Memory.Unicode)   : ProcedureReturn *Memory\u : EndProcedure
  Procedure.q PeekValI_W(*Memory.Word)      : ProcedureReturn *Memory\w : EndProcedure
  Procedure.q PeekValI_DUMMY(*Memory)       : ProcedureReturn #False    : EndProcedure
  Global PeekValIStep, PeekValIType
  ; Public
  PeekValI = @PeekValI_DUMMY()
  Procedure.i PeekValIStep()
    ProcedureReturn PeekValIStep
  EndProcedure
  Procedure.i GetPeekValIType()
    ProcedureReturn PeekValIType
  EndProcedure
  Procedure.i SetPeekValIType(DataType)
    Select DataType
      Case #PB_Ascii     : PeekValI = @PeekValI_A() : PeekValIStep = SizeOf(Ascii)
      Case #PB_Byte      : PeekValI = @PeekValI_B() : PeekValIStep = SizeOf(Byte)
      Case #PB_Character : PeekValI = @PeekValI_C() : PeekValIStep = SizeOf(Character)
      Case #PB_Integer   : PeekValI = @PeekValI_I() : PeekValIStep = SizeOf(Integer)
      Case #PB_Long      : PeekValI = @PeekValI_L() : PeekValIStep = SizeOf(Long)
      Case #PB_Quad      : PeekValI = @PeekValI_Q() : PeekValIStep = SizeOf(Quad)
      Case #PB_Unicode   : PeekValI = @PeekValI_U() : PeekValIStep = SizeOf(Unicode)
      Case #PB_Word      : PeekValI = @PeekValI_W() : PeekValIStep = SizeOf(Word)
      Default            : ProcedureReturn #False
    EndSelect
    PeekValIType = DataType
    ProcedureReturn #True
  EndProcedure
EndModule
DeclareModule pbex_Memory_PokeValI
  Prototype PokeValI(*Memory, Value) : Global PokeValI.PokeValI
  Declare.i PokeValIStep()
  Declare.i GetPokeValIType()
  Declare.i SetPokeValIType(DataType)
EndDeclareModule
Module        pbex_Memory_PokeValI
  EnableExplicit
  Procedure PokeValI_A(*Memory.Ascii    , Value) : *Memory\a = Value : EndProcedure
  Procedure PokeValI_B(*Memory.Byte     , Value) : *Memory\b = Value : EndProcedure
  Procedure PokeValI_C(*Memory.Character, Value) : *Memory\c = Value : EndProcedure
  Procedure PokeValI_I(*Memory.Integer  , Value) : *Memory\i = Value : EndProcedure
  Procedure PokeValI_L(*Memory.Long     , Value) : *Memory\l = Value : EndProcedure
  Procedure PokeValI_Q(*Memory.Quad     , Value) : *Memory\q = Value : EndProcedure
  Procedure PokeValI_U(*Memory.Unicode  , Value) : *Memory\u = Value : EndProcedure
  Procedure PokeValI_W(*Memory.Word     , Value) : *Memory\w = Value : EndProcedure
  Procedure PokeValI_DUMMY(*Memory      , Value) :                   : EndProcedure
  Global PokeValIStep, PokeValIType
  ; Public
  PokeValI = @PokeValI_DUMMY()
  Procedure.i PokeValIStep()
    ProcedureReturn PokeValIStep
  EndProcedure
  Procedure.i GetPokeValIType()
    ProcedureReturn PokeValIType
  EndProcedure
  Procedure.i SetPokeValIType(DataType)
    Select DataType
      Case #PB_Ascii     : PokeValI = @PokeValI_A() : PokeValIStep = SizeOf(Ascii)
      Case #PB_Byte      : PokeValI = @PokeValI_B() : PokeValIStep = SizeOf(Byte)
      Case #PB_Character : PokeValI = @PokeValI_C() : PokeValIStep = SizeOf(Character)
      Case #PB_Integer   : PokeValI = @PokeValI_I() : PokeValIStep = SizeOf(Integer)
      Case #PB_Long      : PokeValI = @PokeValI_L() : PokeValIStep = SizeOf(Long)
      Case #PB_Quad      : PokeValI = @PokeValI_Q() : PokeValIStep = SizeOf(Quad)
      Case #PB_Unicode   : PokeValI = @PokeValI_U() : PokeValIStep = SizeOf(Unicode)
      Case #PB_Word      : PokeValI = @PokeValI_W() : PokeValIStep = SizeOf(Word)
      Default            : ProcedureReturn #False
    EndSelect
    PokeValIType = DataType
    ProcedureReturn #True
  EndProcedure
EndModule
DeclareModule pbex_Memory_PeekValF
  Prototype.d PeekValF(*Memory) : Global PeekValF.PeekValF
  Declare  .i PeekValFStep()
  Declare  .i GetPeekValFType()
  Declare  .i SetPeekValFType(DataType)
EndDeclareModule
Module        pbex_Memory_PeekValF
  EnableExplicit
  Procedure.d PeekValF_F(*Memory.Float)  : ProcedureReturn *Memory\f : EndProcedure
  Procedure.d PeekValF_D(*Memory.Double) : ProcedureReturn *Memory\d : EndProcedure
  Procedure.d PeekValF_DUMMY(*Memory)    : ProcedureReturn #False    : EndProcedure
  Global PeekValFStep, PeekValFType
  ; Public
  PeekValF = @PeekValF_DUMMY()
  Procedure.i PeekValFStep()
    ProcedureReturn PeekValFStep
  EndProcedure
  Procedure.i GetPeekValFType()
    ProcedureReturn PeekValFType
  EndProcedure
  Procedure.i SetPeekValFType(DataType)
    Select DataType
      Case #PB_Float  : PeekValF = @PeekValF_F() : PeekValFStep = SizeOf(Float)
      Case #PB_Double : PeekValF = @PeekValF_D() : PeekValFStep = SizeOf(Double)
      Default         : ProcedureReturn #False
    EndSelect
    PeekValFType = DataType
    ProcedureReturn #True
  EndProcedure
EndModule
DeclareModule pbex_Memory_PokeValF
  Prototype PokeValF(*Memory, Value) : Global PokeValF.PokeValF
  Declare.i PokeValFStep()
  Declare.i GetPokeValFType()
  Declare.i SetPokeValFType(DataType)
EndDeclareModule
Module        pbex_Memory_PokeValF
  EnableExplicit
  Procedure PokeValF_F(*Memory.Float , Value.d) : *Memory\f = Value : EndProcedure
  Procedure PokeValF_D(*Memory.Double, Value.d) : *Memory\d = Value : EndProcedure
  Procedure PokeValF_DUMMY(*Memory   , Value.d) :                   : EndProcedure
  Global PokeValFStep, PokeValFType
  ; Public
  PokeValF = @PokeValF_DUMMY()
  Procedure.i PokeValFStep()
    ProcedureReturn PokeValFStep
  EndProcedure
  Procedure.i GetPokeValFType()
    ProcedureReturn PokeValFType
  EndProcedure
  Procedure.i SetPokeValFType(DataType)
    Select DataType
      Case #PB_Float  : PokeValF = @PokeValF_F() : PokeValFStep = SizeOf(Float)
      Case #PB_Double : PokeValF = @PokeValF_D() : PokeValFStep = SizeOf(Double)
      Default         : ProcedureReturn #False
    EndSelect
    PokeValFType = DataType
    ProcedureReturn #True
  EndProcedure
EndModule
DeclareModule pbex_Memory
  ; pbex_Memory_PeekVal
  Macro PeekVal(pSource, pDestination)                      : pbex_Memory_PeekVal::PeekVal(*Source, *Destination)                      : EndMacro
  Macro PeekValStep(GetDestinationStep)                     : pbex_Memory_PeekVal::PeekValStep(GetDestinationStep)                     : EndMacro
  Macro GetPeekValType(GetDestinationType)                  : pbex_Memory_PeekVal::GetPeekValType(GetDestinationType)                  : EndMacro
  Macro SetPeekValType(SourceDataType, DestinationDataType) : pbex_Memory_PeekVal::SetPeekValType(SourceDataType, DestinationDataType) : EndMacro
  ; pbex_Memory_PeekValI
  Macro PeekValI(pMemory)         : pbex_Memory_PeekValI::PeekValI(pMemory)         : EndMacro
  Macro PeekValIStep()            : pbex_Memory_PeekValI::PeekValIStep()            : EndMacro
  Macro GetPeekValIType()         : pbex_Memory_PeekValI::GetPeekValIType()         : EndMacro
  Macro SetPeekValIType(DataType) : pbex_Memory_PeekValI::SetPeekValIType(DataType) : EndMacro
  ; pbex_Memory_PokeValI
  Macro PokeValI(pMemory, Value)  : pbex_Memory_PokeValI::PokeValI(pMemory, Value)  : EndMacro
  Macro PokeValIStep()            : pbex_Memory_PokeValI::PokeValIStep()            : EndMacro
  Macro GetPokeValIType()         : pbex_Memory_PokeValI::GetPokeValIType()         : EndMacro
  Macro SetPokeValIType(DataType) : pbex_Memory_PokeValI::SetPokeValIType(DataType) : EndMacro
  ; pbex_Memory_PeekValF
  Macro PeekValF(pMemory)         : pbex_Memory_PeekValF::PeekValF(pMemory)         : EndMacro
  Macro PeekValFStep()            : pbex_Memory_PeekValF::PeekValFStep()            : EndMacro
  Macro GetPeekValFType()         : pbex_Memory_PeekValF::GetPeekValFType()         : EndMacro
  Macro SetPeekValFType(DataType) : pbex_Memory_PeekValF::SetPeekValFType(DataType) : EndMacro
  ; pbex_Memory_PokeValF
  Macro PokeValF(pMemory, Value)  : pbex_Memory_PokeValF::PokeValF(pMemory, Value)  : EndMacro
  Macro PokeValFStep()            : pbex_Memory_PokeValF::PokeValFStep()            : EndMacro
  Macro GetPokeValFType()         : pbex_Memory_PokeValF::GetPokeValFType()         : EndMacro
  Macro SetPokeValFType(DataType) : pbex_Memory_PokeValF::SetPokeValFType(DataType) : EndMacro
EndDeclareModule
Module        pbex_Memory
  ; blind
EndModule
Falls es jemanden interessiert, so kann ich die Ankündigung machen, dass es vermutlich nicht mehr lange Dauert bis die sfxr-Portierung fertig ist (falls nicht etwas wichtigeres dazwischenkommt)! Die GUI läuft schon fehlerfrei, nur bei der Wave-Erstellung habe ich doch irgendwo einen bösen Fehler eingebaut... Sind sicher die Zeiger schuld! :mrgreen:
PureBasic 5.73 LTE x86/x64 | Windows 7 (x64)
auser
Beiträge: 58
Registriert: 17.05.2011 10:56

Re: C/C++ zu PB: Reference, Dereference, Pointer, By Referen

Beitrag von auser »

Regenduft hat geschrieben:Naja... geht doch fast so... Allerdings wäre ein richtiges ByRef schon schön! Besonders für Strings, da es dort ja keine Lösung gibt. Auch nicht mit Zeigern und/oder gepiekste und gestupse.
Dieses "doch fast so" ist aber der springende Punkt. Ans Ziel kommst du in dem Fall in allen 3 Sprachen. Aber je nachdem welche Sprache das ist muss der Programmierer halt mehr oder weniger Aufwand betreiben um dort hin zu kommen. Eine Struktur die genau ein Feld hat finde ich ziemlich fail. Funktioniert schon aber ich finde das ist ein unschöner Workaround.

Strings gibt's schon eine Lösung. Musste halt Pieksen und Popeln ;) ...und dabei aufpassen daß du keinen Overflow produzierst (also eigentlich so ziemlich das selbe wie du es in C auch machen würdest):

Code: Alles auswählen

Procedure test(*a)
  PokeS(*a,"Hello world")
EndProcedure

Define x.s = Space(256)
test(@x)
Debug(x)
Oder in C:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

void test(char * a) {  
  strcpy(a,"Hello world"); 
}

int main() {
  char x[256];
  test(x);
  printf("%s\n",x);
}
Richtigerweise müsstest du in PB und auch C eigentlich noch ein Argument in der Funktion einbauen etwa test(*a, size.i) um zu vermeiden daß du in der Funktion mehr in den Speicher schreibst als du vorher reserviert hast. Weil den Speicher reservierst du sowohl in PB als auch in C schon außerhalb der Funktion.

In C++ sieht es hingegen so aus:

Code: Alles auswählen

#include <iostream>
#include <string>

using namespace std;

void test(string& a) {
  a = "Hello world";
}

int main () {
  string x; 
  test(x);
  cout << x << '\n';
}
Antworten