BlitzMax mit Assembler und C/(C++)

Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Neue Antwort erstellen

Thunder

Betreff: BlitzMax mit Assembler und C/(C++)

BeitragDi, Okt 26, 2010 16:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

in diesem Tutorial, das voraussichtlich aus drei Teilen bestehen wird, möchte ich erklären, wie man BlitzMax-Code dazu bringt mit Assembler oder C/C++ zu interagieren. Auf C++ werde ich nicht explizit eingehen, weil ich mich damit nicht wirklich beschäftige und weil das meiste, was nicht mit Objektorientierung zusammenhängt in C und C++ gleich ist.

Tiefergehende Erklärungen sind blau markiert und zum allgemeinen Verständnis nicht unbedingt notwendig.
Wichtige Anmerkungen sind rot gefärbt.

Teil 1 Grundlagen zur Zusammenarbeit von BlitzMax- und C-Code

Code!
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Global x:Int=758, y:Int=579

Code: [AUSKLAPPEN]
//imp1.c
int addnumbers(int zahl1, int zahl2){
   return zahl1+zahl2;
}


Die C-Funktion mit Namen 'addnumbers' nimmt zwei Integer als Argumente und gibt die Summe der beiden zurück. Nicht wirklich sinnvoll, aber genug für eine Demonstration.
Um den C-Code in den BlitzMax-Code einzubinden muss man ihn mit 'Import' importieren:
BlitzMax: [AUSKLAPPEN]
Import "imp1.c" 'Import nimmt den Namen der Datei als Parameter

Wichtig: Die C-Codedatei muss auf '.c' enden! (für C++ entweder auf '.cpp' oder auf '.cxx')
Mit Import eingefügte Code-Dateien werden zuerst kompiliert und dann statisch dazugelinkt. Auf Windows wird COFF, auf Linux ELF als Objektdatei-Format verwendet.

Ein Import alleine reicht nicht um die Funktion direkt aufrufen zu können und das ist auch gut so. In einem Extern-Block im BlitzMax-Code muss man im die Funktionen, die man importieren will definieren. Funktionen, die zwar im C-Code vorhanden sind, aber nicht im Extern-Block definiert wurden, können auch nicht von BlitzMax aus aufgerufen werden.
Ein Extern-Block anhand unseres Beispiels könnte so aussehen:

BlitzMax: [AUSKLAPPEN]
Extern
Function addnumbers:Int(zahl1:Int,zahl2:Int) 'Funktion wird im Extern-Block definiert
EndExtern


Strings und Instanzen von User-Defined Types können nicht ohne weiteres von einer C-Funktion bearbeitet werden. Denn die eigentliche String-Variable bzw. die eigentliche Variable, die die Instanz hält, ist nur ein Zeiger (eine Referenz) auf eine Struktur. Das Problem ist, dass diese Strukturen auch versteckte Daten enthalten.
Für Strings habe ich eine Lösung parat, doch dazu später.

Es lassen sich nicht nur externe Funktionen einbinden, sondern auch externe, globale Variablen. Das hat Sinn, wenn diese hauptsächlich von externen Funktionen gebraucht werden, aber auch manchmal von BlitzMax-Funktionen. Ein Beispiel für eine häufig benutzte, externe Variable ist 'AppTitle'.

Wenn man also in einem C-Code zum Beispiel eine globale Integervariable definiert, wie hier:
Code: [AUSKLAPPEN]
//imp2.c
int x=50;

void print_x(void){ // die Funktion soll zeigen, wie C die Variable x "sieht"
   printf("[C] X: %d\n",x);
}


und diesen C-Code importiert, ist die Variable, genauso wie eine Funktion, nicht ohne weiteres ansprechbar. Man muss sie, innerhalb eines Extern-Blocks mit Global definieren:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "imp2.c"

Extern
Global x% 'die Variable bekommt den Wert, der ihr in der C-Datei zugewiesen wurde.
Function print_x()
EndExtern

WriteStdout "[BlitzMax] X: "+x+"~n"
print_x();
x:+5
WriteStdout "[BlitzMax] X: "+x+"~n"
print_x();
'Soll zeigen, dass sich x für den BlitzMax-Code und den C-Code ändert.
End



Der Startwert von x wird außerhalb (in der exvar.c) festgelegt. Von dort wird gestartet. Bei einem Import einer Variable kann sie von Innen genauso angesprochen werden, wie von Außen. Das kann kompliziert und gefährlich werden (besonders bei Zeigern)! Trotzdem kann es sehr nützlich sein.

Wichtig! Der Startwert einer extern deklarierten Variablen kann nicht im Extern-Block angegeben oder geändert werden!
Wichtig! Die globale Variable darf in C/C++ nicht als 'static' deklariert werden!
Wichtig! Ist die Variable in C/C++ als 'const' deklariert, muss sie trotzdem mit Global importiert werden. Daraus folgt, dass BlitzMax nicht weiß, dass es eigentlich eine Konstante ist und bei einer Manipulation an der Variable gibt es eine EXCEPTION_ACCESS_VIOLATION.


BlitzMax bietet noch ein Feature, das sich auf Variablen und Funktionen anwenden lässt. Man kann die externe Funktion innerhalb des BlitzMax-Codes umbenennen. Außerhalb wird sie immernoch mit ihrem Originalnamen angesprochen, doch im BlitzMax-Quelltext muss sie mit dem angegebenen Namen angesprochen werden. Dieses Umbenennen hat aber keine Auswirkung auf die Ansprechbarkeit der Variable oder der Funktion.

Ich nehme den Code aus dem Beispiel 1, modifiziere aber den BlitzMax-Code leicht:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "imp1.c"
Extern
Function AddNum:Int(zahl1:Int,zahl2:Int)="addnumbers" ' 'addnumbers' ist der externe Name
EndExtern
Global x:Int=758, y:Int=579
WriteStdout "Summe: "+AddNum(x,y)+"~n" 'im BlitzMax-Code kann ich die Funktion nur noch mit AddNum ansprechen
End


Das ganze funktioniert mit externen Variablen genauso, mit einer Zuweisung per = und einem String der den Originalnamen der externen Funktion/Variable angibt. Es mag sehr falsch aussehen, aber innerhalb des Extern-Blocks ist das legal.

Um BlitzMax-Funktionen in C aufrufen zu können, muss man nur im C-Code vor den Funktionsnamen ein 'bb_' stellen. Ein Beispiel:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "imp3.c"
Extern
Function cmain()
EndExtern

cmain()
End

Function AddNumbers%(x%,y%)
Return x+y
EndFunction

Code: [AUSKLAPPEN]
//imp3.c
/*
 Bei mir hat es ohne Vorwärtsdeklaration der Funktion bb_AddNumbers funktioniert. Sollte das bei euch nicht so sein, so müsst ihr folgende Zeile in den C-Code einfügen:
 int bb_AddNumbers(int,int);
*/
void cmain(void){
   printf("5+10 = %d\n",bb_AddNumbers(5,10));
}


Um eine globale Variable aus dem BlitzMax-Code zu teilen, muss man, wie bei Funktionen im C-Code ein 'bb_' vor den eigentlichen Namen stellen und die Variable im C-Code als extern deklarieren:

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "imp4.c"
Global x%=50
Extern
Function cmain()
EndExtern

cmain()
End

Code: [AUSKLAPPEN]
//imp4.c
extern int bb_x; //diese Zeile ist wichtig!

void cmain(void){
   printf("X: %d\n",bb_x);
}


So, das wars erst Mal.
Ich freue mich über konstruktive Vorschläge zur Erweiterung und über Korrekturen, falls ich irgendwo einen Fehler gemacht oder etwas schlecht erklärt habe.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

Thunder

BeitragDi, Okt 26, 2010 16:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Teil 2 Grundlagen zur Zusammenarbeit von BlitzMax- und Assemblercode

Gleich vorweg zwei Dinge:
1. Das ist kein Grundlagen-Tutorial zu Assembler, sondern ein Tutorial für die, die Assembler schon können und es in Verbindung mit BlitzMax verwenden wollen. Ich werde daher am Assemblercode nur Besonderheiten, die man im Zusammenhang mit BlitzMax braucht, erklären.
2. BlitzMax ist für den flat assembler (fasm) ausgelegt, daher werde ich auch nur mit Code für den flat assembler arbeiten. Trotzdem möchte ich hier gesagt haben, dass man auch mit anderen Assemblern entwickeln kann. Eine knappe Erklärung gibt es am Ende dieses Teils.

Beim flat assembler wird das Ausgabeformat, das der assembler am Ende produziert, in der Datei festgelegt und nicht von einem Kommandozeilenparameter. Das heißt auf Windows muss am Anfang jeder fasm-Assembler-Datei die Zeile
Code: [AUSKLAPPEN]
format MS COFF

und auf Linux die Zeile
Code: [AUSKLAPPEN]
format ELF

stehen.

MS COFF steht für Microsoft Common Object File Format. Das COFF Format gibt es schon sehr lange, es wurde mit Unix eingeführt (nicht die erste Version von Unix, laut Wikipedia Unix V). Microsoft hat dieses Objektcodeformat übernommen und etwas modifiziert.
ELF steht für Executable and Linkable Format. Es hat auf vielen Unixsystemen das COFF Format abgelöst und wird heute auf den meisten Linux-Distributionen und einigen anderen Betriebssystemen als Objektdateiformat verwendet. Außerdem wird es auf diesen Systemen meistens gleichzeitig auch als ausführbares Format verwendet - daher executable and linkable.


Wenn man in Assembler eine Funktion schreibt und die in BlitzMax aufrufen möchte, so muss man noch folgendes beachten:
1. Der Funktionsname muss mit einer Underline ( '_' ) beginnen. Einfach weil es sich eingebürgert hat, dass jeder Compiler vor jeden Funktionsnamen eine Underline macht, damit es keine Überschneidungen mit Assemblerbefehlen gibt.
2. Das Label, das die Funktion einleitet muss als public deklariert sein, damit der Name in die Objektdatei geschrieben wird.
3. Die Funktion muss, wie auch bei C, im BlitzMax-Code in einem Extern-Block deklariert werden (und zwar ohne die vorangehende Underline).
4. Die Assemblerdatei muss die Endung .s haben.

Und weil Code mehr sagt als tausend Worte, hier ein Beispiel:

Code: [AUSKLAPPEN]
;asm_beispiel1.s
format MS COFF ; Für Linux mit ELF
public _Add
_Add:
   mov eax,[esp+4]
   mov ebx,[esp+8]
   add eax,ebx
ret

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "test.s"
Extern
Function Add%(x%,y%)
EndExtern
WriteStdout "1337 + 314159 = "+Add(1337,314159)
End


Importieren von Variablen
Auch Variablen können (wie mit C) in BlitzMax sichtbar gemacht werden. Diese müssen, wie Funktionen, im Assemblercode die Underline als Präfix erhalten und als public deklariert sein. In BlitzMax muss die Variable in einem Extern-Block als Global deklariert werden. Das Umbenennen einer Variable funktioniert wie in Teil 1, da es eine Eigentheit von BlitzMax und nicht von C oder Assembler ist. Hier ein Beispiel:

Code: [AUSKLAPPEN]
;test.s
format MS COFF

public _Variable
_Variable:
dd 1337

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "test.s"

Extern
Global v:Int="Variable"
EndExtern

WriteStdout "Variable: "+v+"~n"


BlitzMax braucht für Variablen immer nur ihre 'wahre' Größe. Das heißt, eine Variable vom Typ Byte ist wirklich nur ein Byte groß, ein Variable vom Typ Short ist auch nur ein Word groß ... (ist nicht selbstverständlich)
Die Werte der Variablen müssen dementsprechend mit db, dw beziehungsweise dd festgelegt werden. Zeiger haben eine Größe von zwei Words. Strings sind keine Primitive, dennoch wäre eine Stringvariable nichts anderes als zwei Words, die auf eine Blitzmax-spezifische Stringstruktur zeigen.
Wie man mit Strings umgehen kann (direkt und indirekt), kommt im dritten Teil dieser Tutorialserie.

Float und Double
Mit Floats und Doubles habe ich in Assembler noch nicht gearbeitet, daher kann ich dazu nichts sagen, werde es aber bei Gelegenheit hier einfügen. Bei der Arbeit mit Floats und Doubles möchte ich aber eher von Assembler abraten, da C an dieser Stelle stark vereinfacht und trotzdem sehr gut optimiert.


BlitzMax-Funktionen in Assembler aufrufen
Ich habe bis jetzt die Erfahrung gemacht, dass alle Funktionen, die in BlitzMax-Modulen deklariert wurden '_bb' als Präfix erhalten. Man muss also die Funktion, die man in Assembler aufrufen will, mit diesem Präfix als extern deklarieren. Hier ein kleines Beispiel:
Code: [AUSKLAPPEN]
format MS COFF

extrn _bbWriteStdout
extrn _bbReadStdin

public _cat

_cat:
   push ebp
   mov ebp,esp
   sub esp,8
   call _bbReadStdin
   mov [ebp-4],eax
   push eax
   call _bbWriteStdout
   add esp,4
   mov eax,[ebp-4]
   mov esp,ebp
   pop ebp
ret

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "test.s"

Extern
Function cat$()
EndExtern

Local s$
Repeat
s=cat()
WriteStdout "~n"
Until s.length=0

End

Wichtig! Es muss immer darauf geachtet werden, dass die Funktion, die man im Assemblercode aufrufen will, auch wirklich (in BlitzMax) importiert wird! Sonst bekommt ihr böse Linkerfehler!

Wichtig! selbstdefinierte Funktionen bekommen ein anderes Präfix; nämlich '_bb_' !

BlitzMax mit anderen Assemblern
bmk ruft von selbst auf Linux- und Windowssystemen den flat assembler auf, wenn eine Assemblerdatei importiert werden soll. Daher hat man die wenigsten Probleme, wenn man fasm verwendet. Ein einfacher Weg, einen anderen Assembler zu verwenden ist, einfach nach jeder Änderung an der Assemblerdatei jenen Assembler aufzurufen und die Assemblerdatei nach MS COFF bzw. ELF zu assemblieren und mit Import die entstandene Objektdatei zu importieren.
  • Zuletzt bearbeitet von Thunder am So, Jan 09, 2011 16:01, insgesamt 2-mal bearbeitet

Thunder

BeitragDi, Okt 26, 2010 16:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Teil 3 Tipps und Tricks im Umgang mit BlitzMax in Verbindung mit C/C++ oder Assembler

Dieser (letzte) Teil der Tutorialreihe beschäftigt sich tiefer mit BlitzMax und zeigt einige Tipps, mit denen mancher Programmcode kürzer wird und einige Tricks im Zusammenhang mit Assembler/C(++).

Datentypen und ihre Größen

    Byte - 8 Bit (ohne Vorzeichen)
    Short - 16 Bit (ohne Vorzeichen)
    Int - 32 Bit (mit Vorzeichen)
    Long - 64 Bit (mit Vorzeichen)
    Float - 32 Bit (mit Vorzeichen)
    Double - 64 Bit (mit Vorzeichen)
    Alle Zeiger - 32 Bit


Tipps zu Zeigern
Wenn man einen Zeiger übergibt, übergibt man eigentlich (auf 32-Bit PCs) eine Adresse mit einer Größe von 4 Byte. Ich kann also einen BlitzMax
Integer an eine C-Funktion übergeben, die eigentlich einen Zeiger (egal welchen Datentyps) als Argument erwartet, weil beide 4 Byte groß sind - einfach indem ich im Extern Block von BlitzMax statt des Zeigertyps den Integertyp angebe. Niemand wird was davon erfahren (nicht der Compiler, nicht der Linker ...). Geht natürlich genauso in die andere Richtung.
Das kann nützlich sein, weil es (meiner Meinung nach) unnötige Typumwandlungen in BlitzMax oder C ersparen kann. Schluss mit Meldungen wie "passing arg 1 of 'xyz' makes integer from pointer without a cast".

Paramaterattribut Var
Was der BlitzMax-Befehl 'Var', der nach einer Parametervariable in einer Funktionsdeklaration stehen darf, genau macht, muss erst Mal geklärt werden:

- Der Programmierer wird dazu gezwungen eine Variable zu übergeben (es darf kein direkter Wert übergeben werden)
- Die Variable wird per call-by-reference übergeben (d.h. es wird ein Zeiger auf Ihren Speicherbereich übergeben. Innerhalb der Funktion wird bei jedem Aufscheinen der Variable, statt der Adresse des Zeigers der Wert an der Adresse des Zeigers verwendet -> eine Manipulation innerhalb der Funktion wird sich auch auf den Wert der Variable außerhalb der Funktion auswirken)

Das ist ein sehr nützlicher Befehl, doch um das ganze auf Code-Ebene zu erklären, habe ich dieses Beispiel geschrieben:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Local v%=20

Function f1(x:Int Var)
x:+5
EndFunction

f1(v)
' v hat jetzt den Wert 25

' ... ist nichts anderes als ...

Function f2(x:Int Ptr)
x[0]:+5 'Pointer dereferenzieren und 5 addieren
EndFunction
' f2 macht genau dasselbe wie f1.
' Die vom BlitzMax-Compiler generierten Assemblercodes für beide Funktionen sind exakt gleich.

f2(Varptr(v)) 'Ich übergebe den Zeiger auf den Speicherbereich der Variable, ermittelt durch die Funktion 'VarPtr'

' v hat jetzt den Wert 30


Das heißt also, wenn ich einem Parameter einer (von BlitzMax aus gesehen) externen Funktion das Var-Attribut gebe, muss ich in C/C++ oder Assembler einen Zeiger erwarten.

AT&T-Syntax
Wer zwar Assembler-Code schreiben will, aber die Intel-Syntax nicht mag (und nicht den Umweg gehen will, den ich im letzten Teil kurz ansprach), kann sich eine C-Funktion schreiben, die Inline-Assembler enthält. Das funktioniert, weil der gcc standardmäßig nach AT&T-Syntax Assembler kompiliert. Da der C-Compiler aber den Header und den Footer einer Funktion selber schreibt ist man an diesen Rahmen gebunden.

String übergeben
Einen String übergeben ist eine leichte Sache. Gegeben sei eine Variable s vom Typ String und eine externe C-Funktion die einen Zeiger auf char (char*) erwartet. Dann markiere ich diesen Parameter in BlitzMax als 'Byte Ptr' und übergebe ihm einfach s oder s.ToCString().
Die Methode ToCString der Klasse String wandelt (wie der Name schon sagt) eine BlitzMax-Stringstruktur in einen einfachen C-String um. Normalerweise ist der Aufruf der Methode nicht explizit notwendig - in dem Fall macht BlitzMax die Typumwandlung automatisch.

String zurückgeben
Strings zurückgeben ist, soweit ich weiß, nicht einfach (wenn jemand einen einfacheren Weg kennt, bitte melden). Ich importiere dazu das Modul pub.stdc, allokiere in der externen Funktion Speicher für den String (Wichtig! Der Speicher muss dynamisch allokiert sein. Es darf kein lokales Char-Array verwendet werden!), beschreibe ihn (er muss mit dem Nullterminierungszeichen; "~0" , \0 , Chr(0)) enden und gebe die Adresse zurück.
In BlitzMax nehme ich die Adresse und wandle den C-String mit Hilfe der Funktion String.FromCString() in einen String um.
Nachdem ich das getan habe, gebe ich den Speicher des C-Strings, den ich nicht mehr brauche, mit free_ (aus pub.stdc) frei.
BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import pub.stdc
Import "string.c"

Extern
Function Rot13:Byte Ptr(s:Byte Ptr) 'einfach ein z an das String-Symbol anhängen
EndExtern

WriteStdout "Dein Name: "
Local s$=ReadStdin().Trim()
'Die Replaces sind nur da um Probleme auf den verschiedenen
'Plattformen zu verhindern.
Local cstring:Byte Ptr=Rot13(s)
Local str_cstring$=String.FromCString(cstring)
WriteStdout "nach Rot13: "+str_cstring+"~n"
free_(cstring)
End

Code: [AUSKLAPPEN]
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

char* Rot13(char *s){
   char *x=malloc(strlen(s)+1),*y=x;
   for(;*s!=0;s++,y++){
      if(isalpha(*s)) *y=(*s-((isupper(*s))?65:97)+13) % 26+(isupper(*s)?65:97);
      else *y=*s;
   }
   *y=0;
   return x;
}


Direkter Stringzugriff - Übergabe an Nicht-BlitzMax-Code
Ich hab mich ein bisschen in von Blitzmax generierten Assemblercodes umgesehen und dabei herausgefunden welchem Schema Strings folgen. Ein Beispielstring ("hallo welt!") sähe so aus:
Code: [AUSKLAPPEN]
   dd   _bbStringClass
   dd   2147483647
   dd   11
   dw   104,97,108,108,111,32,119,101,108,116,33


Für Nicht-Assemblerianer:
- Das ganze ist eine Struktur. C-Programmierer können sich also eine struct mit folgendem Aufbau vorstellen:
- Der erste Integer (4 Byte Wert) enthält einen Zeiger auf die Stringklasse. Was da alles genau drinnen ist, weiß ich auch nicht.
- Der zweite Integer enthält den Wert (256^4/2-1). Dabei handelt es sich wahrscheinlich um die Maximallänge des Strings (bin mir aber nicht sicher).
- Der dritte Integer enthält die Länge des Strings.
- Darauf folgt ein Short-Array (Array aus 2 Byte Werten) mit jeweils einem Zeichen (BlitzMax dürfte UTF-8 Strings verwenden, daher hat ein ASCII-Zeichen im BlitzMax-String denselben Wert, ist aber ein Short groß).

Eine struct für C sähe so aus:
Code: [AUSKLAPPEN]
struct BMXString{
   void *class;
   int max;
   int len;
   unsigned short string[];
};


Echte Assemblerprogrammierer werden aus der Struktur und der vorangehenden Erklärung die nötigen Informationen zur Umsetzung in Assembler herauslesen können! Wink

Wichtig ist, dass die externe Funktion nicht ein Objekt dieser Struktur, sondern einen Zeiger auf so eine Struktur erwarten muss. Außerdem wird, soweit ich das beobachtet habe, ein Zeiger auf den Originalstring, nicht auf eine Kopie, übergeben. Das heißt, Änderungen haben einen direkten Effekt auf den String in BlitzMax.

Wichtig! Das Schreiben auf Strings mit der direkten Methode ist absolut nicht zu empfehlen. Wenn der neue String nämlich länger ist als der ursprüngliche, kann das zu ungültigen Speicherzugriffen führen!

Hier ist ein einfaches Programm, das einen in BlitzMax definierten String in einer C-Funktion ausgibt:
Code: [AUSKLAPPEN]
struct BMXString{
   void *class;
   int max;
   int len;
   unsigned short string[];
};

void sout(struct BMXString *s){
   int i;
   for(i=0;i<s->len;i++)
      putchar((char) s->string[i]);
}

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.blitz
Import "test.c"
Global s$="hallo welt!"

Extern
Function sout(str$)
EndExtern

sout(s)
End


Falls ich noch ein paar Hacks entdecke oder auf welche aufmerksam gemacht werde, werden die natürlich reineditiert.
  • Zuletzt bearbeitet von Thunder am So, Jan 09, 2011 16:36, insgesamt 2-mal bearbeitet
 

Macintosh

BeitragFr, Nov 12, 2010 18:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr schön... und vorallem nützlich :)
Danke

Thunder

BeitragSo, Jan 09, 2011 16:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Tutorialserie ist jetzt fertig und ich freue mich über Fragen, Wünsche, Anregungen und/oder Beschwerden!
Und bitte entschuldigt den sanften Push. Ich wollte nur, dass die Änderungen auch bemerkt werden.

mfg Thunder
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

mpmxyz

BeitragSo, Jan 09, 2011 17:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Schönes Tutorial!
Dieses Zeichen kennzeichnet C-Strings: $z
Man kann dieses anscheinend auch bei Rückgaben verwenden:
BlitzMax: [AUSKLAPPEN]
  Function lua_getinfo:Int (lua_state:Byte Ptr, what$z, ar:lua_Debug Ptr)    ' no ~0 expected
'[...]
Function lua_getlocal$z (lua_state:Byte Ptr, ar:lua_Debug Ptr, n:Int) ' no ~0 expected

mfG
mpmxyz
Edit:
Hast du dir die Codes der BlitzMax-Strings durchgelesen?
Da gibt es zum Beispiel auch das hier:
Code: [AUSKLAPPEN]
struct BBString{
   BBClass*   clas;
   int      refs;
   int      length;
   BBChar   buf[];
};

(im Modul brl.Blitz "blitz_string.h")
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
  • Zuletzt bearbeitet von mpmxyz am So, Jan 09, 2011 17:31, insgesamt 2-mal bearbeitet

Lord Stweccys

BeitragSo, Jan 09, 2011 17:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Klasse Tutorial, schöne Übersicht außerdem.

Bei BlitzMax ist das ganze ja nur sehr schäbig dokumentiert, also sind solche Tutorials garantiert hilfreich.

Danke für das Tut Very Happy


Mfg,
LordSt

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group