Was verstehe ich an der Verwendung von Macros falsch?

Anfängerfragen zum Programmieren mit PureBasic.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Was verstehe ich an der Verwendung von Macros falsch?

Beitrag von Toshy »

Also ich nutze zwar schon seit einiger Zeit ein wenig Macros, aber ich merke ich muß da was ganz falsch machen.
Ich dachte, das alles was innerhalb des Macros steht und dem entspricht was in als Parameter angegeben ist ersetzt wird. Ersetzt wird dann einfach durch das, was im Macroaufruf steht.
So habe ich das verstanen,
Aber habe ich ihn dem Macro ein Strukturelement, des Name TEILWEISE durch das Macro erstezt werden soll, so klappt das nicht.
Also bei

Code: Alles auswählen

Macro xxx(ersetzen)
...()\blabla_ersetzen =....
wird in der Struktur nichts ersetzt.
Was mich aber mehr wundert ist, das folgendes nicht geht:

Code: Alles auswählen

Macro macro_bqi_GetUniCodePointerData(InformationLevelStrukturElementName, InformationLevelStrukturElementErrorName, InformationLevelKonstante)
            Debug "InformationLevelStrukturElementErrorName: " 
          EndMacro
          macro_bqi_GetUniCodePointerData(BQI_BatterySerialNumber, BQI_BatterySerialNumber_ERROR, #BatterySerialNumber)
Was verstehe ich falsch bei der Verwendung von Macros?
Bei dem Strukturelement hätte ich es noch verstehen können, da vielleicht beim kompelieren was durch den 1pass-Kompiler (denke ich mal) auf Grund der Codestruktur dies nicht geht. Aber das andere Beispiel kapiere ich absolut nicht.

Getestet mit PB4 im Debuggermodus.

Gruß
Toshy
1. Win10
PB6.1
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Code: Alles auswählen

Macro xxx(ersetzen)
...()\blabla_ersetzen =.... 
muss so heißen:

Code: Alles auswählen

Macro xxx(ersetzen)
...()\blabla_#ersetzen =.... 

Code: Alles auswählen

Macro macro_bqi_GetUniCodePointerData(InformationLevelStrukturElementName, InformationLevelStrukturElementErrorName, InformationLevelKonstante)
            Debug "InformationLevelStrukturElementErrorName: "
          EndMacro
          macro_bqi_GetUniCodePointerData(BQI_BatterySerialNumber, BQI_BatterySerialNumber_ERROR, #BatterySerialNumber)
muss so heißen:

Code: Alles auswählen

Macro Quote
  "
EndMacro

Macro macro_bqi_GetUniCodePointerData(InformationLevelStrukturElementName, InformationLevelStrukturElementErrorName, InformationLevelKonstante)
  Debug Quote InformationLevelStrukturElementErrorName: Quote
EndMacro
macro_bqi_GetUniCodePointerData(BQI_BatterySerialNumber, BQI_BatterySerialNumber_ERROR, BatterySerialNumber)
Das Quote-Macro ist hierfür ein Hilfsmittel.
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Also wenn ich das richtig sehe, darf an also in Macros weder das "Doppelhäkchen" noch die "Raute" im Code nutzen, in Macros mit Parameter. Muß ich beides mit "Hilfsmacros" darstellen!?
Ähem, jetzt wo ich schreibe, sehe ich das es doch geht, oder auch nicht!? Bin doch etwas verwirrt. In der Hilfe steht das Beispiel

Code: Alles auswählen

Beispiel: Fortgeschrittenes mehrzeiliges Makro

  Macro DoubleQuote
    "
  EndMacro

  Macro Assert(Expression)
    CompilerIf #PB_Compiler_Debugger  ; 'Assert' (Erklärung) nur im Debug-Modus aktivieren
      If Expression
        Debug "Assert (Line " + Str(#PB_Compiler_Line) + "): " + DoubleQuote#Expression#DoubleQuote
      EndIf
    CompilerEndIf
  EndMacro

  Assert(10 <> 10) ; Wird nichts anzeigen
  Assert(10 <> 15) ; Sollte die Erklärung anzeigen

In der Debugzeile wird ja doch das DoubleQuote genutzt, aber nicht überall. Wieso kann man nicht

Code: Alles auswählen

Debug "Assert (Line " + Str(#PB_Compiler_Line) + "): " + "#Expression#"
schreiben?
Muß das Hilfsmacro immer dann nehmen, wenn der zu ersetzende Ausdruck innerhalb von Häkchen steht? Weshalb?

Was ist mit der Raute? Bei der Konstante passiert nichts und "Expression" ist es ein Verbindungszeichen. Welche regel gibt es da? Ich kapiere das noch nicht.

Folgendes:

Code: Alles auswählen

Macro DoubleQuote
  "
EndMacro

Macro Assert(Expression,w)
  CompilerIf #PB_Compiler_Debugger  ; 'Assert' (Erklärung) nur im Debug-Modus aktivieren
  If Expression
    Debug "wAssert (Line " + Str(#PB_Compiler_Line) + "): " + DoubleQuote#Expression#DoubleQuote
  EndIf
  CompilerEndIf
EndMacro

Assert(10 <> 10,kkk) ; Wird nichts anzeigen
Assert(10 <> 15,kkk) ; Sollte die Erklärung anzeigen
Was muß ich machen, damit das "w" in der Debugzeile durch die Übergabe ersetzt wird? Habe das bisher nicht hinbekommen. Es klappt einfach nicht.
Es sollte also "kkkAssert (Line....." ausgegeben werden.
Wenn ich die korrekte Übersetzung sehen würde, könnte das mein Verständis doch um einige erweitern :-)

Um zu meinem eigenen Code zu kommen will ich Folgenden Code in ein Macro umwandeln

Code: Alles auswählen

     SizeOfBQI_BatteryUniqueID = 1
                  dwOut = 0
                  bqi\InformationLevel = #BatteryUniqueID 
                  ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID = _AllocateMemory(SizeOfBQI_BatteryUniqueID*2+2) 
                  Repeat 
                    ReturnDeviceIoControl2 = DeviceIoControl_(hBattery, #IOCTL_BATTERY_QUERY_INFORMATION, @bqi, SizeOf(bqi), ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID,SizeOfBQI_BatteryUniqueID*2+2, @dwOut, #Null)
                    ReturnGetLastErrorDeviceIoControl2 = GetLastError_()
                    setlasterror_(0)
                    If dwOut = 0 And (ReturnGetLastErrorDeviceIoControl2 = #ERROR_INSUFFICIENT_BUFFER Or ReturnGetLastErrorDeviceIoControl2 = #ERROR_MORE_DATA)
                      SizeOfBQI_BatteryUniqueID + 1
                      ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID = _ReAllocateMemory(ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID,SizeOfBQI_BatteryUniqueID*2+2)
                    EndIf
                  Until (dwOut <> 0 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER) Or (ReturnGetLastErrorDeviceIoControl2 <> 0 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA)
                  If ReturnDeviceIoControl2 <> 0 And ReturnGetLastErrorDeviceIoControl2 = 0
                  Else
                    ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID_ERROR = ReturnGetLastErrorDeviceIoControl2
                  EndIf 
                  If ReturnGetLastErrorDeviceIoControl2 <> 0
                    ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID_ERROR = ReturnGetLastErrorDeviceIoControl2
                    Debug "BQI_BatteryUniqueID_ERROR: " + Str(ll_EnumeratingBatteryDevices()\BQI_BatteryUniqueID_ERROR)
                  EndIf
Macro macro_bqi_GetUniCodePointerData(InformationLevelName)
...
EndMacro

Da man leider nicht sehen kann, an welcher Stelle ein Fehler ist, wenn man das Programm startet, komme ich nicht (mit Sicherheit) weiter.
Nach einigem testen würde ich es so machen, bin mir aber nicht sicher:

Code: Alles auswählen

   Macro macro_bqi_GetUniCodePointerData(InformationLevelName)
                    SizeOfBQI_#InformationLevelName = 1
                    Debug "SizeOfBQI_BatterySerialNumber= " + Str(SizeOfBQI_BatterySerialNumber)
                    dwOut = 0
                    bqi\InformationLevel = #InformationLevelName
                  Debug " bqi\InformationLevel= " + Str( bqi\InformationLevel)
                  ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName = _AllocateMemory(SizeOfBQI_#InformationLevelName*2+2) 
                  Debug DoubleQuote ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName= DoubleQuote + Str( ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName)
                    Repeat 
                      ReturnDeviceIoControl2 = DeviceIoControl_(hBattery, #IOCTL_BATTERY_QUERY_INFORMATION, @bqi, SizeOf(bqi), ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName,SizeOfBQI_#InformationLevelName*2+2, @dwOut, #Null)
                      ReturnGetLastErrorDeviceIoControl2 = GetLastError_()
                      setlasterror_(0)
                      If dwOut = 0 And (ReturnGetLastErrorDeviceIoControl2 = #ERROR_INSUFFICIENT_BUFFER Or ReturnGetLastErrorDeviceIoControl2 = #ERROR_MORE_DATA)
                        SizeOfBQI_BatteryUniqueID + 1
                        ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName = _ReAllocateMemory(ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName,SizeOfBQI_#InformationLevelName*2+2)
                      EndIf
                    Until (dwOut <> 0 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER) Or (ReturnGetLastErrorDeviceIoControl2 <> 0 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA)
                    If ReturnDeviceIoControl2 <> 0 And ReturnGetLastErrorDeviceIoControl2 = 0
                    Else
                      ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName#_ERROR = ReturnGetLastErrorDeviceIoControl2
                    EndIf 
                    If ReturnGetLastErrorDeviceIoControl2 <> 0
                      ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName#_ERROR = ReturnGetLastErrorDeviceIoControl2
                      Debug DoubleQuote#BQI_#InformationLevelName#_ERROR: DoubleQuote + Str(ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName#_ERROR)
                    EndIf
             EndMacro
Wie ich gerade sehe, ist die Zeile

Code: Alles auswählen

       Debug DoubleQuote#BQI_#InformationLevelName#_ERROR: DoubleQuote + Str(ll_EnumeratingBatteryDevices()\BQI_#InformationLevelName#_ERROR)
            
nicht korrekt, denn nach dem ersten DoubleQuote wird im Ausgabefenster das Zeichen "#" mit ausgegeben, besser gesagt, die Ausgabe fängt in dieser Zeile mit dem "#" an.
1. Win10
PB6.1
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Zuerstmal die zugegebenermaßen etwas umständliche Korrektur deines
zweiten Codes:

Code: Alles auswählen

Macro DoubleQuote
  "
EndMacro

Macro Assert(Expression,w)
  CompilerIf #PB_Compiler_Debugger
  If Expression
    Debug DoubleQuote w DoubleQuote + "Assert (Line " + Str(#PB_Compiler_Line) + "): " + DoubleQuote#Expression#DoubleQuote
  EndIf
  CompilerEndIf
EndMacro

Assert(10 <> 10, kkk) ; Wird nichts anzeigen
Assert(10 <> 15, kkk) ; Sollte die Erklärung anzeigen
Wenn in einem Macro ein String durch Anführungszeichen definiert ist, wird
darin kein Parameter ersetzt:

Code: Alles auswählen

Macro DQ
  "
EndMacro

;doof wird nicht ersetzt, da in Anführungszeichen
;para2 wird ersetzt und zusammengefügt mit Raute
;Anstelle von DQ stehen _nach_ dem Zusammensetzen die Anführungszeichen
Macro Test(para1, para2)
  Debug "Hirni ist para1" + DQ#para2#_blabla#DQ
EndMacro

Test(schlau, Jawoll)
Und jetzt wegen deinem letzten Code. Versuch mal das hier, ist aber
ungetestet:

Code: Alles auswählen

Macro DQ
  "
EndMacro

Macro macro_bqi_GetUniCodePointerData(ILN)
  SizeOfBQI_#ILN = 1
  Debug "SizeOfBQI_BatterySerialNumber= " + Str(SizeOfBQI_BatterySerialNumber)
  dwOut = 0
  bqi\InformationLevel = #ILN
  Debug " bqi\InformationLevel= " + Str(bqi\InformationLevel)
  ll_EnumeratingBatteryDevices()\BQI_#ILN = _AllocateMemory(SizeOfBQI_#ILN * 2 + 2)
  Debug "ll_EnumeratingBatteryDevices()\BQI_" + DQ#ILN#DQ + "= " + Str(ll_EnumeratingBatteryDevices()\BQI_#ILN)
  
  Repeat
    ReturnDeviceIoControl2 = DeviceIoControl_(hBattery, #IOCTL_BATTERY_QUERY_INFORMATION, @bqi, SizeOf(bqi), ll_EnumeratingBatteryDevices()\BQI_#ILN, SizeOfBQI_#ILN * 2 + 2, @dwOut, #Null)
    ReturnGetLastErrorDeviceIoControl2 = GetLastError_()
    setlasterror_(0)
    If dwOut = 0 And (ReturnGetLastErrorDeviceIoControl2 = #ERROR_INSUFFICIENT_BUFFER Or ReturnGetLastErrorDeviceIoControl2 = #ERROR_MORE_DATA)
      SizeOfBQI_BatteryUniqueID + 1
      ll_EnumeratingBatteryDevices()\BQI_#ILN = _ReAllocateMemory(ll_EnumeratingBatteryDevices()\BQI_#ILN, SizeOfBQI_#ILN * 2 + 2)
    EndIf
  Until (dwOut <> 0 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER) Or (ReturnGetLastErrorDeviceIoControl2 And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_INSUFFICIENT_BUFFER And ReturnGetLastErrorDeviceIoControl2 <> #ERROR_MORE_DATA)
  If ReturnDeviceIoControl2 = 0 Or ReturnGetLastErrorDeviceIoControl2
    ll_EnumeratingBatteryDevices()\BQI_#ILN#_ERROR = ReturnGetLastErrorDeviceIoControl2
  EndIf
  If ReturnGetLastErrorDeviceIoControl2
    ll_EnumeratingBatteryDevices()\BQI_#ILN#_ERROR = ReturnGetLastErrorDeviceIoControl2
    Debug "BQI_" + DQ#ILN#DQ + "_ERROR: " + Str(ll_EnumeratingBatteryDevices()\BQI_#ILN#_ERROR)
  EndIf
EndMacro
Toshy
Beiträge: 713
Registriert: 22.03.2005 00:29
Computerausstattung: Computer und Strom vorhanden
Wohnort: LK Wolfenbüttel

Beitrag von Toshy »

Danke erstmal für deine intensive Hilfe.
Ich werde das in Kürze mal testen bzw. den Code noch anpassen.
Wenn ich das nun richtig sehe, dann haben Macros doch in der Praxis einiges an Einschränkungen. Es ist also leider nicht so, daß man den normalen Code einfach nur durch "Macro & EndMacro" einklammern kann und dann einfach den zu ersetzten Code durch den Ausdruck ersetzt (eventl. mit dem Verbindungszeichen), sondern den Code sogar zum teil umstellen muß.

Warum aber ist es nicht einfach so, das wirklich einfach nur 1:1 der Quellcode ersetzt wird bevor umgewandelt wird. So kommt es doch zwangsläufig zu Problemen. Man muß sicher sein, das man den Code 100%ig richtig anpaßt, denn eine Kontrolle ist direkt nicht möglich. Es kommen ja auch nur Fehlermeldungen, wenn man bestimmte Fehler macht (unbekannte Struktur oder so), Wenn man aber einen Variablennamen oder ähnliches ersetzt, dann bemerkt man den Fehler nicht, da einfach eine neue Variable "erstellt" wird.

Noch was, wenn man also innerhalb von im Quellcode eingegebenen "Zeichenketten" einen Ausdruck ersetzten will, muß man dies wohl mit dem Hilfsmacro machen. Da aber Leerzeichen wohl verschluckt werden (aber wohl nicht immer) sollte man diese wohl IMMER wieder extre mit z.B. " " einfügen. Alles andere wäre wohl nicht so ganz sicher, richtig!?
Bis später

[edit=140220071609]Habe jetzt etwas getestet, so scheint es zu klappen. Muß jetzt nur ein bissl aufpassen wenn ich Code in Macrocode "umwandele". Mal schauen ob ich es die nächsten Tage auch noch hinbekomme.[/edit]
Zuletzt geändert von Toshy am 14.02.2007 17:10, insgesamt 1-mal geändert.
1. Win10
PB6.1
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> dann bemerkt man den Fehler nicht, da einfach eine neue Variable "erstellt" wird.

für solche eventualitäten empfielt sich EnableExplicit.
das ist sowieso ne gute sache, und wenn man mit so komplexen,
kryptischen konstrukten arbeiten will wie du, ist es unverzichtbar.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten