Hallo,
kann mir einer von euch die Vorteile von "#define" / "Inline" (Makro)
gegenüber einer Funktion, bzw. anderstrum erklären?
Gemeint ist folgendes:
1
#define sbi(p,n) (p) |= (1<<n)
vs.
1
voidpi(floatuebergabe1)
2
{
3
returnuebergabe1*3.14;
4
}
Zugegeben, beide Teile machen etwas anderes (hab das schnell
zusammenkopiert), aber man kann sowohl die PI-Berechnung als Makro als
auch als Funktion ausführen.
Worin liegen also die einzelnen vorteile?
Danke
tom schrieb:> Hallo,>> kann mir einer von euch die Vorteile von "#define" / "Inline" (Makro)> gegenüber einer Funktion, bzw. anderstrum erklären?
Ein Makro (#define) ist nur eine dumme Textersetzung die vor dem
Compilen vorgenommen wird. Eine Funktion ist eine dem Compiler bekannte
Einheit, bei der Typüberprüfungen bei den Argumenten und Rückgabewert
vorgenommen werden und die einen Scope hat.
> Worin liegen also die einzelnen vorteile?
Mit Makros handelt man sich eine Menge Probleme ein, zB reserviert ein
Makro seinen Namen global und wenn man versehentlich den Namen irgendwo
anders noch verwendet gibts obskure Compilerfehler. inline-Funktionen
haben den Nachteil dass sie keinen beliebigen Code generieren können, zB
kann eine inline-Funktion keine Funktionen definieren. Dafür werden aber
die Argumente nicht versehentlich mehrfach ausgewertet, man kann lokale
temporäre Variablen definieren, die Typen der Argumente und Rückgabewert
werden vom Compiler geprüft etc.
Wegen der genannten Nachteile sollte man Makros so weit wie möglich
vermeiden und nur dann verwenden, wenn man die gleiche Funktionalität
nicht durch inline-Funktionen erhalten kann. Das gilt im übrigen auch
für Konstanten:
Grundsätzlich gebe ich Dr. Sommer recht, hätte aber noch ein paar
Anmerkungen:
das Ersetzen von Makros durch inline-Funktionen setzt immer einen gut
optimierenden Compiler voraus - hat man den nicht, können Makros
erhebliche Geschwindigkeitsvorteile bringen. Es lohnt als an kritischen
Stellen immer ein Blick auf den produzierten Assembler-Code. Historisch
resultieren ja viele Makros aus nicht so guten Optimierungen
makros können selten bis nie vollständig ersetzt werden, es ist also
wichtig dass man makros beherrscht, sie lesen kann, und auch Tricks wie
grundsätzliches Klammern der Argumente, temporäre Variablen zur
verhinderung der Mehrfachauswertung, sowie den do { ... } while (0)
Ausdruck kennt.
Ein Praxisbeispiel, welches man ohne Makros nicht hinbekommt:
Michael Reinelt schrieb:> das Ersetzen von Makros durch inline-Funktionen setzt immer einen gut> optimierenden Compiler voraus - hat man den nicht, können Makros> erhebliche Geschwindigkeitsvorteile bringen.
Wenn der verwendete Compiler inlinen nicht beherrscht, würde ich mein
Geld zurück verlangen und/oder GCC oder Clang verwenden...
> Es lohnt als an kritischen> Stellen immer ein Blick auf den produzierten Assembler-Code.
Das ja.
> Historisch> resultieren ja viele Makros aus nicht so guten Optimierungen
Oder aus Unwissen :-/
> Ein Praxisbeispiel, welches man ohne Makros nicht hinbekommt:> #define lcd_printf(row,format,...) __lcd_printf(row, PSTR(format), ##> _VA_ARGS_)
In C++ schon:
Etwas mehr Schreibarbeit, viel mehr Sicherheit, viel weniger
Überraschungen, 0 Overhead.
> Will man portabel programmieren (z.B. Win/Unix, oder auch nur für> verschiedene Unix-Flavours, geht ohne #define /und #ifdef) gar nix mehr.
Die man hier aber hoffentlich nur als Schalter verwendet. Wobei es für
diesen häufig auftretenden Fall auch abstrahierende Libraries gibt...
Dr. Sommer schrieb:> Michael Reinelt schrieb:>> das Ersetzen von Makros durch inline-Funktionen setzt immer einen gut>> optimierenden Compiler voraus - hat man den nicht, können Makros>> erhebliche Geschwindigkeitsvorteile bringen.> Wenn der verwendete Compiler inlinen nicht beherrscht, würde ich mein> Geld zurück verlangen und/oder GCC oder Clang verwenden...
Da gehts nicht nur um inline, sondern auch um ein tiefes constant
folding etc. ich hab jetzt (gottseidank :-) keine beispiele bei der
Hand, aber ich hab schon jede Menge programmiert wo es ohne makros
definitiv nicht ging (aus geschwindigkeitsgründen)
>> resultieren ja viele Makros aus nicht so guten Optimierungen> Oder aus Unwissen :-/
oder aus gewohnheit (wie bei mir :-)
>> Ein Praxisbeispiel, welches man ohne Makros nicht hinbekommt:>> #define lcd_printf(row,format,...) __lcd_printf(row, PSTR(format), ##>> _VA_ARGS_)> In C++ schon:>
Ich kann leider kein C++, aber wie kriegst du das PSTR() da rein?
>> Will man portabel programmieren (z.B. Win/Unix, oder auch nur für>> verschiedene Unix-Flavours, geht ohne #define /und #ifdef) gar nix mehr.> Die man hier aber hoffentlich nur als Schalter verwendet. Wobei es für> diesen häufig auftretenden Fall auch abstrahierende Libraries gibt...
oder die autoconf-Hölle :-(
> das Ersetzen von Makros durch inline-Funktionen setzt immer einen> gut optimierenden Compiler voraus
1975 hatten Kernighan und Ritchie noch keinen optimierenden Compiler.
Damals mussten die halt Inline-Optimierungen noch irgendwie zurecht
tricksen. Hat sich inzwischen erledigt.
... und unter den Mikrocontroller Entwicklern findest du recht viele
Leute, die jedes Bit genau unter Kontrolle haben wollen. Die sich nicht
drauf verlassen wollen, dass der Compiler es schon irgendwie richtig
macht.
Michael Reinelt schrieb:> Es lohnt als an kritischen> Stellen immer ein Blick auf den produzierten Assembler-Code.
Wobei hier "kritische Stelle" als: "Ich habe gemessen/simuliert, dass
diese Stelle meinen Code um x ms verlangsamt. Akzeptabel wären aber nur
y ms, weil bei längerer Laufzeit..... " definiert ist und nicht als "Ich
habe mal gehört, dass XY() langsam ist und habe das diffuse Gefühl,
meinen Code irgendwie optimieren zu müssen, weil embedded und so und
weil Makros professioneller aussehen."
Michael Reinelt schrieb:> Da gehts nicht nur um inline, sondern auch um ein tiefes constant> folding etc. ich hab jetzt (gottseidank :-) keine beispiele bei der> Hand, aber ich hab schon jede Menge programmiert wo es ohne makros> definitiv nicht ging (aus geschwindigkeitsgründen)
Was fürn Compiler war denn das?
> oder aus gewohnheit (wie bei mir :-)
Hoffentlich muss dann keiner deinen Code weiterverwenden und sucht sich
dann einen Wolf nach Makros die in irgendwelchen Headern definiert sind
und später tretminenartig für Probleme sorgen...
> Ich kann leider kein C++, aber wie kriegst du das PSTR() da rein?
Kommt drauf an wie das mit dem PSTR funktioniert... Im Zweifelsfall
immer im Usercode (vergessen resultiert ja hoffentlich in einem
Compiler-Error), denn da gehört die Speicherart sowieso hin. Variadische
Argumente weiterleiten ist jedenfalls kein Problem.
Kein Name schrieb:> Die sich nicht> drauf verlassen wollen, dass der Compiler es schon irgendwie richtig> macht.
Und deren Arbeitszeit scheinbar so billig ist dass es sich lohnt jedes
Bit einzeln zu betrachten anstelle einen richtigen Compiler zu kaufen?
Thomas schrieb:> und weil Makros professioneller aussehen."
An Makros sieht gar nichts professionell aus, denn die sind nur eine
dumme Textersetzung wie sie zu Zeiten der Makroassembler verwendet
wurde. Professionell möchte man Features wie Scope & Typsystem verwenden
um Fehler zu vermeiden/finden.
Dr. Sommer schrieb:> Michael Reinelt schrieb:>> ich hab schon jede Menge programmiert wo es ohne makros>> definitiv nicht ging (aus geschwindigkeitsgründen)> Was fürn Compiler war denn das?
hach, das ist lange her... Turbo-C, irgendein Watcom-Zeugs, vermutlich
Intel, irgendein Ding auf einer VAX 11/780, diverse Compiler auf HP/UX,
Irix, Digital,... frag mich lieber welcher Compiler nicht betroffen
war :-)
> Hoffentlich muss dann keiner deinen Code weiterverwenden und sucht sich> dann einen Wolf nach Makros die in irgendwelchen Headern definiert sind> und später tretminenartig für Probleme sorgen...
Ach komm... man kann auch mit makros sauber programmieren. oder bist du
ein Anhänger der "goto ist böse" Fraktion?
> Kommt drauf an wie das mit dem PSTR funktioniert... Im Zweifelsfall> immer im Usercode (vergessen resultiert ja hoffentlich in einem> Compiler-Error), denn da gehört die Speicherart sowieso hin.
#define PSTR(s) ((const PROGMEM char *)(s))
Vergessen liefert keinen Fehler. Und in den user-Code gehört das nicht,
wenn der Code portabel sein soll.
Michael Reinelt schrieb:> Ach komm... man kann auch mit makros sauber programmieren. oder bist du> ein Anhänger der "goto ist böse" Fraktion?
Nanana..
Kein richtiger, fähiger Programmierer wird je sowas wie 'goto' als böse
und verschmähenswert ansehen. Sowas tun nur die Halbgebildeten, die eine
Programmiersprache auswendig gelernt haben und deshalb mental nicht über
den Dingen stehen.
Aber: Makros sind heutzutage MIST, denn sie tragen ganz gründlich zur
Unverständlichkeit einer Quelle bei. Schau dir mal die Quelle von
Nuvoton's USB Handler an. Da möchte man deren Urheber am liebsten
köpfen, dann erwürgen dann.. (frei nach Osmin)
Und im krassen Gegensatz zu unserem Dr.Dolittle sehe ich #define als
wesentlich besser an als sein Gebräu:
Dr. Sommer schrieb:> #define SIZE 10> ist viel gefährlicher als> static const size_t SIZE = 10;
Grund: ein #define wird vor dem eigentlichen Übersetzen aufgelöst und
kann (wenn man es nicht in einen überall eingebundenen Header schreibt)
deshalb keine Seiteneffekte in anderen Quellen haben. Ebenso belegt
etwas, das per #define erklärt wird, keinerlei Speicherplatz und
reserviert auch keinen Namen im Code. Bei seinem Code wird
sinnloserweise ein Stück ROM belegt und dessen Name muß bis zum Linker
mit durchgeschleift werden. Von der für ein reibungsloses Miteinander
von unterschiedlichen Moduln nötigen Kapselung kann da keine Rede
sein.
Ansonsten nur noch eines: Wer meint, ohne Makros keinen effektiven Code
schreiben zu können ("aber ich hab schon jede Menge programmiert wo es
ohne makros definitiv nicht ging (aus geschwindigkeitsgründen)"), hat
seine Software strukturell "unoptimal" angelegt.
W.S.
Michael Reinelt schrieb:> hach, das ist lange her... Turbo-C, irgendein Watcom-Zeugs, vermutlich> Intel, irgendein Ding auf einer VAX 11/780, diverse Compiler auf HP/UX,> Irix, Digital,... frag mich lieber welcher Compiler nicht betroffen> war :-)
Ohgott. Damals. :D
>> Hoffentlich muss dann keiner deinen Code weiterverwenden und sucht sich>> dann einen Wolf nach Makros die in irgendwelchen Headern definiert sind>> und später tretminenartig für Probleme sorgen...> Ach komm... man kann auch mit makros sauber programmieren. oder bist du> ein Anhänger der "goto ist böse" Fraktion?
Man kann, ja, und hin und wieder sind Makros unumgänglich und goto
praktisch. Aber wenn man sich sowas wie die CMSIS anguckt, in der
9000000 Makros mit kurzen Namen (gefährlich) definiert sind, möchte man
Makros lieber gleich ganz verbieten.
>> Kommt drauf an wie das mit dem PSTR funktioniert... Im Zweifelsfall>> immer im Usercode (vergessen resultiert ja hoffentlich in einem>> Compiler-Error), denn da gehört die Speicherart sowieso hin.>> #define PSTR(s) ((const PROGMEM char *)(s))
Also nur ein cast? casten kann man auch in C++:
> Vergessen liefert keinen Fehler. Und in den user-Code gehört das nicht,> wenn der Code portabel sein soll.
Aber in den LCD-Code gehört eine Angabe wo der Speicher hinkommt? Was
wenn man doch RAM-Daten an die Funktion übergeben soll? Da würd ich
lieber das PSTR überall wo nötig in den User-Code packen und auf
Plattformen wo es nicht gebraucht wird es als "nichts" definieren.
W.S. schrieb:> Grund: ein #define wird vor dem eigentlichen Übersetzen aufgelöst
Genau das ist das Problem.
> und> kann (wenn man es nicht in einen überall eingebundenen Header schreibt)> deshalb keine Seiteneffekte in anderen Quellen haben.
Und "static const" zum Glück auch nicht.
W.S. schrieb:> Ebenso belegt> etwas, das per #define erklärt wird, keinerlei SpeicherplatzW.S. schrieb:> Bei seinem Code wird> sinnloserweise ein Stück ROM belegt
Bei einem halbwegs schlauen Compiler (GCC) ist das alles Unsinn und das
"static const" wirkt Speichertechnisch wie ein Literal. In C nur als
Nettigkeit vom Compiler, in C++ vom Standard vorgeschrieben...
W.S. schrieb:> Von der für ein reibungsloses Miteinander> von unterschiedlichen Moduln nötigen Kapselung kann da keine Rede> sein.
Du verstehst unter Kapselung also versteckte globale Variablen? Urks.
Dann verstehst du unter "Objekt" auch bestimmt ".c -Datei". Jedenfalls,
wenn man unbedingt gleich benannte aber unterschiedliche globale
Konstanten in mehreren .c -Dateien haben will, ist das dank "static"
eben kein Problem, da dann eben kein Linker-Symbol angelegt wird.
Vielleicht mal schauen wie C funktioniert bevor man seinen Unsinn
verzapft?
W.S. schrieb:> Ansonsten nur noch eines: Wer meint, ohne Makros keinen effektiven Code> schreiben zu können ("aber ich hab schon jede Menge programmiert wo es> ohne makros definitiv nicht ging (aus geschwindigkeitsgründen)"), hat> seine Software strukturell "unoptimal" angelegt.
Das ist allerdings korrekt.
Dr. Sommer schrieb:> Bei einem halbwegs schlauen Compiler (GCC) ist das alles Unsinn
Schreib du mal keinen Unsinn. Wenn jemald hinschreibt
static const size_t SIZE = 10;
dann ist das eine Konstante im Bereich für konstante Daten (je nach
System kann das ROM sein oder initialisierter RAM) und basta. Der
Compiler hat da ein bissel die Klappe zu halten, weil er die eigentliche
Intention des Schreibers nicht wissen kann. So eine Konstante wird
eigentlich bei allen Systemen bis zum Linker durchgeschleppt und belegt
auch Identifier-Platz.
" Du verstehst unter Kapselung also versteckte globale Variablen? Urks."
Nicht nur. Auch Funktionen, die nur innerhalb des Dunstkreises eines
Moduls, Units, oder wie auch immer man einen zusammengehörigen Block
bezeichnen möchte, vorhanden sind. Kurzum, alles was das aufrufende
Programm nicht wirklich zu wissen braucht. Dazu gehören auch
modulinterne Variablen, die eben NICHT auf dem Stack angelegt sind. Da
ist nix mit Urks.
Und deine Bemerkung über CMSIS möchte ich etwas drastischer ausdrücken:
Man sollte diese Schaumschlägerei ganz und garnicht benutzen. Die
Einführung von abertausenden zusätzlichen Identifiern macht das
programmieren von µC nicht einfacher und übersichtlicher, sondern
wirklich nur fehleranfälliger und nerviger. Ein gleiches Urteil gilt für
die grandiosen Elaborate von ST. Es sind eben Fehlleistungen, die auf
der Annahme beruhen, daß ein Sack von hardware-halb-unabhängigen Namen
besser sei als sich auf das zu beschränken, was im HW-Manual deklariert
ist.
Was man als Programmierer viel besser brauchen kann (könnte..) wären in
sich abgeschlossene Treiber für kompliziertere Peripherie.
Beispielsweise USB, Ethernet lowest level, SDIO. Aber was da angeboten
wird, sind ja ebenfalls nur halbfertige NICHT in sich abgeschlossene
Module, die immer nur einen Rumpf darstellen, der sich so wie er ist,
nicht benutzen läßt.
W.S.
W.S. schrieb:> Ansonsten nur noch eines: Wer meint, ohne Makros keinen effektiven Code> schreiben zu können ("aber ich hab schon jede Menge programmiert wo es> ohne makros definitiv nicht ging (aus geschwindigkeitsgründen)"), hat> seine Software strukturell "unoptimal" angelegt.
Das beantworte ich mal am besten mit deinen Worten:
W.S. schrieb:> Sowas tun nur die Halbgebildeten, die eine> Programmiersprache auswendig gelernt haben und deshalb mental nicht über> den Dingen stehen.
Dr. Sommer schrieb:> Also nur ein cast? casten kann man auch in C++:
Und jetzt gehen wir mal weg von der grauen Theorie ins sehr
farbenprächtige, aber leider auch harte und unfaire real life: dort kann
man sich die Sprache (C oder C++) und den Compiler nicht immer
aussuchen.
W.S. schrieb:> Dr. Sommer schrieb:>> Bei einem halbwegs schlauen Compiler (GCC) ist das alles Unsinn>> Schreib du mal keinen Unsinn. Wenn jemald hinschreibt>> static const size_t SIZE = 10;>> dann ist das eine Konstante im Bereich für konstante Daten (je nach> System kann das ROM sein oder initialisierter RAM) und basta. Der> Compiler hat da ein bissel die Klappe zu halten, weil er die eigentliche> Intention des Schreibers nicht wissen kann. So eine Konstante wird> eigentlich bei allen Systemen bis zum Linker durchgeschleppt und belegt> auch Identifier-Platz.
Schauen wir uns das doch mal im konkreten Beispiel an. Dieser Code:
1
#include<stdint.h>
2
3
staticconstuint8_tSIZE=10;
4
5
uint8_tgetVal(){
6
returnSIZE;
7
}
wird mit "avr-gcc test.c -o test.o -O1" compiled und mit "avr-objdump -d
test.o" disassemblisiert. Es kommt heraus:
1
00000000 <getVal>:
2
0: 8a e0 ldi r24, 0x0A ; 10
3
2: 08 95 ret
Oh Schreck, die Konstante liegt überhaupt nicht seperat im ROM, sondern
wurde vom Compiler in die Instruktion hineinoptimiert! Schauen wir uns
mit "avr-nm test.o" die generierten Linker-Symbole an, ist weit und
breit nichts von "SIZE" zu sehen. Das ändert sich wenn man das "static"
weglässt. Denn "static" bei der Definition globaler Variablen oder
Funktionen bedeutet nichts anderes, als kein Linkersymbol anzulegen...
>> " Du verstehst unter Kapselung also versteckte globale Variablen? Urks."> Nicht nur. Auch Funktionen, die nur innerhalb des Dunstkreises eines> Moduls, Units, oder wie auch immer man einen zusammengehörigen Block> bezeichnen möchte, vorhanden sind. Kurzum, alles was das aufrufende> Programm nicht wirklich zu wissen braucht. Dazu gehören auch> modulinterne Variablen, die eben NICHT auf dem Stack angelegt sind. Da> ist nix mit Urks.
Du solltest mal eine objektorientierte Sprache lernen. Dort lernst du
was Kapselung wirklich bedeutet.
>> Und deine Bemerkung über CMSIS möchte ich etwas drastischer ausdrücken:> Man sollte diese Schaumschlägerei ganz und garnicht benutzen. Die> Einführung von abertausenden zusätzlichen Identifiern macht das> programmieren von µC nicht einfacher und übersichtlicher, sondern> wirklich nur fehleranfälliger und nerviger.
Das Problem ist nur wie sie definiert sind, nämlich als Makros. Wären
sie schön als Variablen/Konstanten definiert könnte man wenigstens C++
verwenden, ein "namespace XX { ... }" um das #include packen und damit
diese Identifier in eine dunkle Ecke schieben. Aber an sowas denken die
Herren E-Techniker & Hardwareentwickler bei ARM und ST nicht. Dass man
eine Menge Identifier braucht ist leider unumgänglich - wenn man 1000
Register hat, braucht man nunmal 1000 Namen dafür... Und es ist ja nicht
so dass andere API's nicht noch viel mehr davon hätten...
> Was man als Programmierer viel besser brauchen kann (könnte..) wären in> sich abgeschlossene Treiber für kompliziertere Peripherie.> Beispielsweise USB, Ethernet lowest level, SDIO. Aber was da angeboten> wird, sind ja ebenfalls nur halbfertige NICHT in sich abgeschlossene> Module, die immer nur einen Rumpf darstellen, der sich so wie er ist,> nicht benutzen läßt.
Das USB-Zeug von denen lässt sich schon nutzen. Aber es hat sogar einen
wunderschönen Buffer-Overflow und ein grauenhaftes Interface.
Michael Reinelt schrieb:> Und jetzt gehen wir mal weg von der grauen Theorie ins sehr> farbenprächtige, aber leider auch harte und unfaire real life: dort kann> man sich die Sprache (C oder C++) und den Compiler nicht immer> aussuchen.
Ja leider. Aber versuchen kann man's ja mal. Für viele
Embedded-Plattformen (AVR, ARM, MIPS, MSP430, ...) gibt es mittlerweile
ja auch C++ Compiler - mindestens mal für alles, für das es einen GCC
oder Clang gibt. Man sollte auch nicht vergessen dass C++ zu 99%
abwärtskompatibel ist - man kann bestehende C-Projekte meist fast
unverändert in einen C++ Compiler stecken und seine C++ Extras dazubauen
Da hätte ich auch mal eine Frage an den Herrn Dr. Sommer.
Das mit static const... leuchtet mir schon ein.
Wie vermeide ich aber in folgendem Beispiel die #defines?
1
#define ENDE_FLAG 0x08
2
...
3
#define ENDE (GPIO0 & ENDE_FLAG)
4
...
5
if (ENDE) tuwas
Wenn ich eine Funktion (mit oder ohne inline) verwende, müßte ich
schreiben:
Peter M. schrieb:> Geht das in C auch ohne die Klammern hinter ENDE?
In C nicht dass ich wüsste. In C++ könnte man sich einen
Konvertierungsoperator schreiben:
1
staticconstENDE_FLAG=0x08;
2
3
class{
4
public:
5
inlineoperatorbool(){
6
returnGPIO0&ENDE_FLAG;
7
}
8
}ENDE;
9
10
intmain(){
11
if(ENDE){
12
...
13
}
14
}
Allerdings sind die Klammern beim ENDE() jetzt auch nicht so
dramatisch...
Danke. In C++ ist das schon eleganter.
Nein. So dramatisch sind die Klammern nicht.
Es sieht halt ohne besser aus. ;)
Dann werde ich mich wohl bei Gelegenheit mal wieder mit C++
beschäftigen. Die Syntax unterscheidet sich da doch schon etwas. Da GCC,
wie ich gelesen habe, auch C-Programme übersetzt, könnte es allerdings
ganz hilfreich sein, einiges von C++ mitzubenutzen.
Btw: fehlt da hinter static const ... nicht ein uint8_t?
Peter M. schrieb:> Dann werde ich mich wohl bei Gelegenheit mal wieder mit C++> beschäftigen. Die Syntax unterscheidet sich da doch schon etwas. Da GCC,> wie ich gelesen habe, auch C-Programme übersetzt, könnte es allerdings> ganz hilfreich sein, einiges von C++ mitzubenutzen.
Ja, und wie gesagt kannst du C-Programme auch einfach als C++
übersetzen. Gibt nur einige wenige Stellen die du evtl. etwas anpassen
musst (sagt dir der Compiler dann).
> Btw: fehlt da hinter static const ... nicht ein uint8_t?
Öhm - ja.
>Mittels #define kann man auch fremdsprachigen Sourcecode in den>C-Compiler reinschieben:
Bloss, dass bei VB der Variable-typ, nicht wie bei C, hinten (mit as
...) angehängt wird.
> Mittels #define kann man auch fremdsprachigen Sourcecode> in den C-Compiler reinschieben:
Stimmt, aber das Beispiel taugt nichts. http://www.ioccc.org
Rainer V. schrieb:> Mittels #define kann man auch fremdsprachigen Sourcecode in den> C-Compiler reinschieben:
Ja super, aber mehr als eine Provokation ist das nicht...