Forum: Mikrocontroller und Digitale Elektronik Funktionsaufruf in C


von Egonwalter M. (heiner1234)


Lesenswert?

Hallo

Ich habe eine Frage zum Aufruf einer Funktion (z.B. ATMega328, 
programmiert in C):
was ist bezgl Speicherplatz und Rechengeschwindigkeit besser
- wenn eine Funktion in main() per for/while Schleife aufgerufen wird
oder
- wenn diese Funktion in main() nur 1mal aufgerufen wird und die 
for/while Schleife
in der Funktion abgearbeitet wird

Danke!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Mikrooptimierungen? Lohnt meistens nicht.

Wenn du die Funktion "static" deklarierst, wird das Ergebnis vermutlich 
komplett identisch sein. Wenn sie nicht "static" ist (und keine 
link-time optimizations aktiv sind), dann könnte der Aufruf der Funktion 
geringfügig mehr Overhead erzeugen. Aber wie geschrieben: das sind 
Mikrooptimierungen. Die retten dir nur dann irgendwas, wenn irgendein 
Timing "auf Kante genäht" ist, ansonsten geht sowas im Rauschen unter.

Strukturiere den Code so, dass du ihn auch in drei Jahren noch gut lesen 
kannst, das ist viel wichtiger.

von micha (Gast)


Lesenswert?

Der "Aufruf" erzeugt einen gewissen Overhead, d.h. besser die Schleife 
in die Funktion packen. Je nach Optimierung kann dann der Aufruf inlined 
und/oder die Schleife selbst entrollt werden. Kommt auf den Code an

von Mucky F. (Gast)


Lesenswert?

Egonwalter M. schrieb:
> was ist bezgl Speicherplatz und Rechengeschwindigkeit besser

Das mal eben zu schreiben und zu compilieren ist keine Lösung?

von Norbert (Gast)


Lesenswert?

Jeder Funktionsaufruf kostet ein paar Prozessor-Zyklen. Auch die lokalen 
Variablen werden jedes Mal angelegt.
Also wäre die zweite Option etwas (geringfügig) günstiger.

Aber: Die Frage ist ob sich das in irgend einer Weise auf das System 
auswirkt. Sinnvollerweise legt man Schleifen dort an wo sie logisch 
gesehen hingehören um das Programm so auch lesbarer zu gestalten.
Alles Andere gehört in die Kategorie ›mehr oder weniger sinnloses 
Optimieren‹.

von Harfner (Gast)


Lesenswert?

Bezüglich Speicher ist es egal. Bezüglich Laufzeit ist die Schleife in 
der Funktion schneller, die Zeit für den Funktionsaufruf fällt nur 
einmal an.
Ob das für Deinen Fall relevant ist, müsste man extra betrachten.

von A. S. (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Ich habe eine Frage zum Aufruf einer Funktion

auch wenn vielleicht schon alles gesagt ist: Funktionen macht man vor 
allem, um Teiloperationen zu separieren/gruppieren. Wenn Du die Funktion 
nur an einer Stelle brauchst, könntest Du sie sonst auch weglassen.

Darum gehört die Schleife dahin, wo die Schleifenbedingungen und äußeren 
Abhängigkeiten thematisch hingehören. Oder anders herum: wo die Summe 
der Parameter einfacher/weniger wird.

Wenn Du ein Beispiel bringst, wirst Du das verstehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. S. schrieb:
> Wenn Du die Funktion nur an einer Stelle brauchst, könntest Du sie sonst
> auch weglassen.

Wie du eben schreibst: zum Separieren/Gruppieren kann das trotzdem 
sinnvoll sein. Wenn man einen Sack voller "static"-Funktionen jeweils 
nur an einer Stelle aufruft, dann packt der Compiler sie ohne mit der 
Wimper zu zucken alle inline in den Aufrufer. Das Ergebnis ist also das 
gleiche, wie wenn man gleich alles in den Aufrufer geschrieben hätte – 
außer dass die Strukturierung in abgetrennte Funktionen in aller Regel 
die Lesbarkeit verbessert. Das allein kann also Grund genug sein, es 
aufzuteilen.

von Stefan F. (Gast)


Lesenswert?

Der Compiler optimiert den Code besser als man denkt. Insofern sollte 
man sich eher darauf konzentrieren, dass der Quelltext für den Menschen 
gut lesbar ist.

Abgesehen davon sind gerade beim AVR Funktionsaufrufe deutlich 
"billiger", als bei vielen anderen Mikrocontrollern.

von piffpoff (Gast)


Angehängte Dateien:

Lesenswert?

Nur um kurz zu zeigen, dass wirklich das gleiche rauskommt.
Ausser das Beispiel ist jetzt übervereinfacht.

von Stefan F. (Gast)


Lesenswert?

Ich verpacke mittlerweile sogar Zugriffe auf einzelne I/O Pins in 
Funktionen, bloß um ihnen sprechende Namen zu geben:
1
void set_power_led_on() {
2
    PORTB |= 1;
3
}
4
5
void set_power_led_off() {
6
   PORTB &= ~1;
7
}
8
9
bool start_button_pressed() {
10
   return (PINB & 2);
11
}

Selbst so etwas wird vom Compiler auf ein Minimum (nämlich einen 
einzigen Assembler Befehl) reduziert, wenn man es mit einem konstanten 
Parameter aufruft:
1
void set_power_led(bool on) {
2
    if (on) PORTB |= 1;
3
    else PORTB &= ~1;
4
}

von P. S. (namnyef)


Lesenswert?

Schreibe den Code so, dass er für einen Menschen gut lesbar ist.

Den schlimmsten Code erzeugen nämlich Programmierer, die glauben 
schlauer als der Compiler zu sein ;)

von Stefan F. (Gast)


Lesenswert?

Wir hatten hier mal einen Assembler Spezi, der meinte, er könne es 
besser als der C Compiler. Die Wette hatte er verloren.

von Stefan F. (Gast)


Lesenswert?

Norbert schrieb:
> Jeder Funktionsaufruf kostet ein paar Prozessor-Zyklen. Auch die lokalen
> Variablen werden jedes Mal angelegt.

Du vergisst, dass der Optimizer den Code umstrukturiert. Dein Satz gilt 
so generell nur, wenn man den Compiler mit Option -O0 aufruft.

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wir hatten hier mal einen Assembler Spezi, der meinte, er könne es
> besser als der C Compiler. Die Wette hatte er verloren.

Naja, und wir hatten Projektansätze wie etwa einen Spektrum-Analyzer für 
den Audio-Bereich oder einen Westminster-Gong, die aber niemals 
benutzbare Realität wurden, bis sich kompetente Assemblerprogrammierer 
ihrer angenommen haben...

Bitte auch das bedenken...

Und weiters bitte ich zu bedenken: fast alles, was unfähige 
C-Programmierer im Bereich Signalanlyse im Laufe der Jahre auf dem AVR8 
gebacken bekommen haben, basiert wiederum auf den FFT-Routinen von Elm 
Chan, der die einerseits auch wieder in Assembler verfaßt hat, 
andererseits aber wohl eindeutig C bevorzugt, wenn möglich.

Sprich: es muß wohl doch was dran sein, dass man mit Asm deutlich 
effizienteren Code erzeugen kann als es ein C-Compiler könnte...

Das kannst du nicht wegdiskutieren.

Mal ganz davon abgesehen: man braucht doch bloß in den Code der Compiler 
selber zu schauen: Assembler ohne Ende. Das wird nur vor den volldummen 
C-only-Schranzen versteckt, aber es ist DA.

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Mal ganz davon abgesehen: man braucht doch bloß in den Code der Compiler
> selber zu schauen

Gemeint ist natürlich nicht der Code der Compiler selber, sondern der 
der Runtime für das Target. Das noch zu Klarstellung.

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> egal was

Tschüss, ich bin raus

von Norbert (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Norbert schrieb:
>> Jeder Funktionsaufruf kostet ein paar Prozessor-Zyklen. Auch die lokalen
>> Variablen werden jedes Mal angelegt.
>
> Du vergisst, dass der Optimizer den Code umstrukturiert. Dein Satz gilt
> so generell nur, wenn man den Compiler mit Option -O0 aufruft.

Das macht er? Macht er das auch wenn die Funktion an verschiedenen 
Stellen (Sourcecode-Dateien) aufgerufen wird und selbst ebenso in einer 
separaten Datei (oder vielleicht in einer Library) liegt?

Aber ich weiß worauf du hinaus willst… ;-)

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> c-hater schrieb:
>> egal was
>
> Tschüss, ich bin raus

Du bist vor allem auch eins: Ein Zitatfälscher. "Egal was" schrieb ich 
an keiner Stelle.

von Euro (Gast)


Lesenswert?

Mal rein "gefühlt": Wenn Du in der main() den Aufruf auf eine Funktion 
mit einer Endlos-Loop findest, und dieses Programm erweitern sollst...

...ok, ich mach das nicht mehr professionell, aber ich würde mich 
verarscht fühlen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Norbert schrieb:
> Macht er das auch

mit -flto ggf. schon

von Sebastian (Gast)


Lesenswert?

c-hater schrieb:
> Stefan ⛄ F. schrieb:
>
>> Wir hatten hier mal einen Assembler Spezi, der meinte, er könne es
>> besser als der C Compiler. Die Wette hatte er verloren.
>
> Naja, und wir hatten Projektansätze wie etwa einen Spektrum-Analyzer für
> den Audio-Bereich oder einen Westminster-Gong, die aber niemals
> benutzbare Realität wurden, bis sich kompetente Assemblerprogrammierer
> ihrer angenommen haben...
> Bitte auch das bedenken...
> Und weiters bitte ich zu bedenken: fast alles, was unfähige
> C-Programmierer im Bereich Signalanlyse im Laufe der Jahre auf dem AVR8
> gebacken bekommen haben, basiert wiederum auf den FFT-Routinen von Elm
> Chan, der die einerseits auch wieder in Assembler verfaßt hat,
> andererseits aber wohl eindeutig C bevorzugt, wenn möglich.
> Sprich: es muß wohl doch was dran sein, dass man mit Asm deutlich
> effizienteren Code erzeugen kann als es ein C-Compiler könnte...
> Das kannst du nicht wegdiskutieren.
> Mal ganz davon abgesehen: man braucht doch bloß in den Code der Compiler
> selber zu schauen: Assembler ohne Ende. Das wird nur vor den volldummen
> C-only-Schranzen versteckt, aber es ist DA.

Ein reflektierter und abwägender Beitrag von c-hater. Lesen war spannend 
-- ich hab die ganze Zeit auf den Holzhammer gewartet und er kam nicht! 
Und bei den volldummen Schranzen ganz zum Schluss war es dann irgendwie 
schon zu spät ...

LG, Sebastian

von Norbert (Gast)


Lesenswert?

Jörg W. schrieb:
> Norbert schrieb:
>> Macht er das auch
>
> mit -flto ggf. schon

OK. Also, ich schreibe eine Funktion welche einen Sack voller lokaler 
Variablen anlegt, verarbeitet und einen Return Wert generiert.
Die packe ich in eine Library.

Und der Compiler zupfelt mir das später auseinander, arrangiert alles 
neu und packt es wo auch immer hin?
Ähm, ich vermute eher nicht.

Aber du schriebst ja auch:  Link-Time Optimierung und ggf

von Dirk B. (dirkb2)


Lesenswert?

Norbert schrieb:
> Jeder Funktionsaufruf kostet ein paar Prozessor-Zyklen. Auch die lokalen
> Variablen werden jedes Mal angelegt.

Das anlegen der Variablen kostet aber keine Zeit.

von (prx) A. K. (prx)


Lesenswert?

Dirk B. schrieb:
> Das anlegen der Variablen kostet aber keine Zeit.

Das Anlegen der ersten Variable kostet Zeit, wenn dafür Platz auf dem 
Stack reserviert wird. Bei Prozessoren, deren Hersteller Rechnungen mit 
dem Stack-Pointer völlig verpennt haben (AVR), kann das auch weitere 
Variablen betreffen.

Jede Variable kostet Zeit, wenn ein zusätzliches Register gesichert 
werden muss.

: Bearbeitet durch User
von Norbert (Gast)


Lesenswert?

Dirk B. schrieb:
> Norbert schrieb:
>> Jeder Funktionsaufruf kostet ein paar Prozessor-Zyklen. Auch die lokalen
>> Variablen werden jedes Mal angelegt.
>
> Das anlegen der Variablen kostet aber keine Zeit.

Auf'm Stack muss der (frame)Pointer angepasst werden. OK, nur wenige 
Zyklen. Lokale Variablen müssen jedes mal initialisiert werden. Auch nur 
wenige Zyklen. Selbst ein lokaler alloca() ist überschaubar.

Was aber wenn ich mit malloc() einen großen Arbeitbereich brauche?
Einmal malloc(), 1.000.000 mal Schleife und arbeiten, einmal free()
oder
1.000.000 mal eine Funktion aufrufen mit jeweils:
malloc(), arbeiten, free()

Es kommt immer auf den jeweiligen Fall an.

von Egonwalter M. (heiner1234)


Lesenswert?

Jörg W. schrieb:
> Mikrooptimierungen? Lohnt meistens nicht.
>
> Strukturiere den Code so, dass du ihn auch in drei Jahren noch gut lesen
> kannst, das ist viel wichtiger.

Hallo an Alle

Vielen Dank für Eure Hilfe!

Jörg W.s Tipp +1!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Norbert schrieb:
> Und der Compiler zupfelt mir das später auseinander, arrangiert alles
> neu und packt es wo auch immer hin?

So ist es. Auch, wenn die Dinger "link-time optimizations" heißen, wird 
in Wirklichkeit nach dem Linken nochmal der Compiler über Teile des 
Codes geschickt. Daher funktioniert es auch nur, wenn man das -flto 
sowohl beim Compilieren als auch beim Linken angibt, denn es wird 
(zumindest habe ich das mal so verstanden) in den Objektdateien dafür 
noch irgendein Zwischencode hinterlegt.

Deine fiktive Bibliothek müsste also ebenfalls ihre Module mit -flto 
compiliert bekommen haben.

> und ggf

Ja, natürlich, Optimierungen sind immer Abwägungen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Norbert schrieb:
> Und der Compiler zupfelt mir das später auseinander, arrangiert alles
> neu und packt es wo auch immer hin?

Mal ein Beispiel.

Wir haben die Datei a.c:
1
#include <avr/io.h>
2
3
void toggle_pin(void) {
4
   PINC = 1;
5
}

Die compilieren wir und packen sie in eine Library:
1
$ avr-gcc -Os -mmcu=atmega328 -flto -c a.c
2
$ avr-ar rv a.a a.o
3
avr-ar: creating a.a
4
a - a.o
5
avr-ar: a.o: plugin needed to handle lto object

Oh! Das mit -flto compilierte Objektmodul hat irgendwas, was eine 
Sonderbehandlung braucht. ;-) (Wusste ich bis jetzt auch noch nicht.)
1
$ avr-ar rv --plugin /usr/local/libexec/gcc/avr/11.2.0/liblto_plugin.so a.a a.o
2
avr-ar: creating a.a
3
a - a.o

Aha. Mit dem passenden Plugin kann er es wirklich.

Nun b.c:
1
#include <avr/io.h>
2
3
extern void toggle_pin(void);
4
5
int main(void)
6
{
7
  DDRC = 1;
8
  for (;;) {
9
    toggle_pin();
10
  }
11
}

Also auch ganz simpel. ;-)

Jetzt alles compilieren und linken:
1
$ avr-gcc -Os -mmcu=atmega328 -flto -c b.c
2
$ avr-gcc -Os -mmcu=atmega328 -flto -o c.elf b.o a.a

Was kommt raus?
1
$ avr-objdump -d c.elf
2
3
c.elf:     file format elf32-avr
4
5
6
Disassembly of section .text:
7
8
00000000 <__vectors>:
9
   0:   0c 94 34 00     jmp     0x68    ; 0x68 <__ctors_end>
10
   4:   0c 94 3e 00     jmp     0x7c    ; 0x7c <__bad_interrupt>
11
[...]
12
00000080 <main>:
13
  80:   81 e0           ldi     r24, 0x01       ; 1
14
  82:   87 b9           out     0x07, r24       ; 7
15
  84:   86 b9           out     0x06, r24       ; 6
16
  86:   fe cf           rjmp    .-4             ; 0x84 <main+0x4>
17
[...]

Also tatsächlich, das komplette "toggle_pin()" hat er in main() inline 
rein bekommen.

von A. S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Wie du eben schreibst: zum Separieren/Gruppieren kann das trotzdem
> sinnvoll sein.

So war das "sonst" gemeint: wenn es nicht um dieses Vorteils wäre.

von Stefan F. (Gast)


Lesenswert?

Mein oben genanntes Beispiel:

> void set_power_led(bool on) {
>     if (on) PORTB |= 1;
>     else PORTB &= ~1;
> }

wird ebenfalls auf einen einzigen Assembler Befehl reduziert, selbst 
wenn es in einer anderen *.c Datei steht, als wo es benutzt wird.

Aber nur, wenn -flto benutzt wird und die Optimierungsstufe mindestens 
auf -O2 oder -Os gestellt ist. Mit -O1 bleibt es ein Funktionsaufruf.

von Teo D. (teoderix)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich verpacke mittlerweile sogar Zugriffe auf einzelne I/O Pins in
> Funktionen, bloß um ihnen sprechende Namen zu geben:
> void set_power_led_on() {
>     PORTB |= 1;
> }

Ich (als Laie) verwende Defines dafür.
Auch der Codegenerator von Microchip, wirft mir für diesen Zweck welche 
aus. Nur ha ich nicht ganz (eher gar nicht:) verstanden, warum das in 
einem do-while Block gepackt wird?-{

#define LED_TEST_SetHigh() do { LATAbits.LATA0 = 1; } while(0)
#define LED_TEST_Toggle() do { LATAbits.LATA0 = ~LATAbits.LATA0; } 
while(0)


Ich vermute mal, das hat was mit den darin enthaltenen, weiteren Defines 
zu tun.

von Stefan F. (Gast)


Lesenswert?

Teo D. schrieb:
> Nur ha ich nicht ganz (eher gar nicht:) verstanden, warum das in
> einem do-while Block gepackt wird?-{

Die defines sind unter gewissen Umständen problematisch. Was du da 
siehst, ist ein Workaround, der diese Probleme vermeiden soll.

Schau mal
https://stackoverflow.com/questions/14041453/why-are-preprocessor-macros-evil-and-what-are-the-alternatives

Den Absatz "Macro expansions can have strange side effects.". In der 
Diskussion werden noch einige weitere potentielle Probleme mit dem 
Markos genannt.

Ich fand Makros früher mal super toll für HW Zugriffe, bin aber auch 
wieder davon weg gekommen, nach ich mit damit selbst ein paar mal ins 
Knie geschossen hatte und auch oft mit unverständlichen Fehlermeldungen 
vom Compiler konfrontiert wurde.

Die vielen Beispiele mit aus heutiger Sicht unnötigen Makros stammen aus 
Zeiten, als der Optimizer im Compiler noch nicht so gut war.

von (prx) A. K. (prx)


Lesenswert?

Stefan ⛄ F. schrieb:
> Die vielen Beispiele mit aus heutiger Sicht unnötigen Makros stammen aus
> Zeiten, als der Optimizer im Compiler noch nicht so gut war.

Explizites Inlining steht im Standard erst mit C99 zur Verfügung. Davor 
gab es das in C++ und als Erweiterung im GNU Compiler.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Explizites Inlining steht im Standard erst mit C99 zur Verfügung.

Also seit 23 Jahren!

von Rolf M. (rmagnus)


Lesenswert?

Teo D. schrieb:
> Nur ha ich nicht ganz (eher gar nicht:) verstanden, warum das in
> einem do-while Block gepackt wird?-{
>
> #define LED_TEST_SetHigh() do { LATAbits.LATA0 = 1; } while(0)
> #define LED_TEST_Toggle() do { LATAbits.LATA0 = ~LATAbits.LATA0; }
> while(0)
>
> Ich vermute mal, das hat was mit den darin enthaltenen, weiteren Defines
> zu tun.

Nein, es hat eher im Gegenteil damit zu tun, wo du die Defines 
verwendest, weil es da recht fiese versteckte Fallstricke geben kann. 
Allerdings ist es in diesem speziellen Fall eigentlich unnötig. 
Interessanter wäre es, wenn da z.B. nicht eine, sondern zwei Zuweisungen 
wären.
1
#define LED_SetBothLEDs() LATAbits.LATA0 = 1; LATbits.LATA1 = 1;

Wenn du jetzt so etwas schreibst:
1
if (irgendwas)
2
    LED_SetBothLEDs();
dann landet nur die erste der beiden Zuweisungen in dem if, und die 
andere wird immer ausgeführt, unabhängig von irgendwas. Das do/while 
sorgt dafür, dass beide im if landen. Mit Funktionen statt Makros sind 
solche work-arounds nicht nötig.

Norbert schrieb:
> Was aber wenn ich mit malloc() einen großen Arbeitbereich brauche?
> Einmal malloc(), 1.000.000 mal Schleife und arbeiten, einmal free()
> oder
> 1.000.000 mal eine Funktion aufrufen mit jeweils:
> malloc(), arbeiten, free()
>
> Es kommt immer auf den jeweiligen Fall an.

Es gibt keinen AVR, auf dem das erste Szenario überhaupt funktionieren 
würde, da du die 1.000.000 allokierten Objekte gar nicht gleichzeitig in 
den Speicher bekämst. Das heißt, es bleibt in so einem Fall nur die 
zweite Option.

(prx) A. K. schrieb:
> Stefan ⛄ F. schrieb:
>> Die vielen Beispiele mit aus heutiger Sicht unnötigen Makros stammen aus
>> Zeiten, als der Optimizer im Compiler noch nicht so gut war.
>
> Explizites Inlining steht im Standard erst mit C99 zur Verfügung. Davor
> gab es das in C++ und als Erweiterung im GNU Compiler.

Das Schlüsselwort "inline" wird nicht dazu verwendet, um dem Compiler zu 
sagen, dass er es inlinen soll. Die Entscheidung, ob er das tut, trifft 
er ganz unabhängig davon. "inline" sorgt nur dafür, dass die one 
definition rule verletzt werden darf.
Bei gcc gibt's noch __attribute__((always_inline)), mit dem man das 
inlining tatsächlich forcieren kann. Wenn das nicht möglich ist, bricht 
er dann auch mit Fehler ab.

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Rolf M. schrieb:
> Wenn du jetzt so etwas schreibst:if (irgendwas)
>     LED_SetBothLEDs();
> dann landet nur die erste der beiden Zuweisungen in dem if, und die
> andere wird immer ausgeführt, unabhängig von irgendwas. Das do/while
> sorgt dafür, dass beide im if landen. Mit Funktionen statt Makros sind
> solche work-arounds nicht nötig.

So einen Fall hatte ich noch nicht. Manchmal hat man auch "Glück". :-}
 Sollte aber bei anzeige mit Macro expansion auffallen.... Wenn einem 
die Fehlermeldungen nicht in die irre führen.


Stefan ⛄ F. schrieb:
> Den Absatz "Macro expansions can have strange side effects.". In der
> Diskussion werden noch einige weitere potentielle Probleme mit dem
> Markos genannt.

Das werde ich mir mal in einer ruhigen Stunde ansehen.

Ich werde aber dabei bleiben, den der Pin-Manager (Codegenerator) ist 
einfach zu bequem und bei meinen "popeligen" µC Projecten, ist das Ganze 
ja auch noch recht übersichtlich.

Danke

von (prx) A. K. (prx)


Lesenswert?

Stefan ⛄ F. schrieb:
> Also seit 23 Jahren!

In der Programmentwicklung bei Mikrocontrollern ist das quasi erst seit 
letzter Woche. Dieses Business folgt Sprachentwicklungen oft nur mit 
sehr langer Verzögerung.

Jene Compiler, die speziell für dieses Genre entwickelt wurden, sind 
selbst oft im Kern uralt und nicht annähernd so optimierungsfreudig wie 
GCC.

Das hat in der Praxis nicht nur Nachteile. Schon viele hat das korrekte 
aber eben sehr flexible Verhältnis des GCC zum Quellcode aus der Kurve 
geworfen. Umordnung und weglassen von Code kommt in der Branche nicht 
immer gut an.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

(prx) A. K. schrieb:
> Schon viele hat das korrekte
> aber eben sehr flexible Verhältnis des GCC zum Quellcode aus der Kurve
> geworfen. Umordnung und weglassen von Code kommt in der Branche nicht
> immer gut an.

Nu ja, die Diskussion ist so alt wie „ohne Optimierung läufts, mit 
nicht“.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Schon viele hat das korrekte aber eben sehr flexible Verhältnis des GCC
> zum Quellcode aus der Kurve geworfen.

IAR optimiert ähnlich rabiat wie GCC und macht zumindest C99 schon sehr 
lange – inklusive vollständiger Standardbibliothek.

von A. S. (Gast)


Lesenswert?

Teo D. schrieb:
> arum das in einem do-while Block gepackt wird?

Das ist ein elegantes Mittel, um das ;- oder }-Problem zu lösen.

Das define sieht aus wie ein Funktionsaufruf. Dahinter sollte im Code 
ein ; stehen.

enthält das #define ein ; oder } am Ende, dann bekommst Du durch Dein ; 
eine Warnung. Und Dinge wie
1
   ...
2
   if(y) 
3
       if(x<8) SetLEDs(x); 
4
       else    SetLEDs(0);
gehen schief ohne dass es auffällt (OK, würde man sagen, selber Schuld 
;-)

Enthält es keines, z.B.:
1
#define SetLEDs(mask) Portx=mask
dann kann der Compiler nicht warnen, wenn Du was abgefahrenes machst, 
z.B.:
1
   SetLEDs(0x18)+4;
2
   SetLEDs(mask)=0;
3
   SetLEDs(0x18)&1;
4
   SetLEDs(=0x18);
5
   void *p; p=&SetLEDs(0); /* komisch, ich muss für den Funktionspointer ein Argument angeben. Vermutlich ein Compiler-Bug, aber es compiliert so!!! */

von Teo D. (teoderix)


Lesenswert?

A. S. schrieb:
> Teo D. schrieb:
>> arum das in einem do-while Block gepackt wird?
>
> Das ist ein elegantes Mittel, um das ;- oder }-Problem zu lösen.

Oh.... Da fällt's einem doch wie Schuppen..... :DDD

Danke

von Ponton 1872 (Gast)


Lesenswert?

c-hater schrieb:
> Und weiters bitte ich zu bedenken: fast alles, was unfähige
> C-Programmierer im Bereich Signalanlyse im Laufe der Jahre auf dem AVR8
> gebacken bekommen haben, basiert wiederum auf den FFT-Routinen von Elm
> Chan, der die einerseits auch wieder in Assembler verfaßt hat,
> andererseits aber wohl eindeutig C bevorzugt, wenn möglich.
> Sprich: es muß wohl doch was dran sein, dass man mit Asm deutlich
> effizienteren Code erzeugen kann als es ein C-Compiler könnte..


Das sind ganz spezielle Funktionen bei denen bestimmte Algorithmen 
möglichst effizient implementiert wurden. Was jedoch bei 99% der 
Anwendungen mittlerweile völliger Blödsinn ist, da blockiert dann vorher 
der Speicherdurchsatz usw.

Ein moderner C Compiler würde vermutlich ähnliche Aufrufe produzieren da 
diesem die meisten Algorithmen und die dazugehörigen Implementierungen 
je nach Architektur bekannt sein sollten.

Du versucht damit gerade Spezialfälle auf allgemeine Anwendungen zu 
übertragen. Und das kannst du bei heutiger Software vergessen.

von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Stefan ⛄ F. schrieb:
> Tschüss, ich bin raus

Ein kurzer Moment der Hoffnung!

Stefan ⛄ F. schrieb:
> Mein oben genanntes Beispiel:

und wieder vorbei /:

Ponton 1872 schrieb:
> Du versucht damit gerade Spezialfälle auf allgemeine Anwendungen zu
> übertragen. Und das kannst du bei heutiger Software vergessen.

Spezialfälle wird es immer geben. Die meisten mir bekannten crypto 
mining Programme nutzen Assembler (natürlich nicht das ganze Programm!).

BG

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stored B. schrieb:
> Die meisten mir bekannten crypto mining Programme nutzen Assembler

Und die umsatzmäßig stärksten Miner nutzen eigene Hardware.

Sollte es also jetzt das Fazit sein, dass man alle Probleme so weit 
zusammen optimiert, bis man für jedes eine eigene Hardware hat? ;-)

Unsinnige Vergleiche … Das Thema war so etwas simples wie ein 
Funktionsaufruf.

: Bearbeitet durch Moderator
von Stored B. (Firma: drx) (umbrecht)


Lesenswert?

Jörg W. schrieb:
> Unsinnige Vergleiche … Das Thema war so etwas simples wie ein
> Funktionsaufruf.

Das ist ja auch das Problem. Solche Themen werden in den meisten C 
Büchern ausführlichst durchgekaut..
Ist diese Interesse nicht da, gibt es immer noch google oder den asm 
Output des Compilers.

Jörg W. schrieb:
> für jedes eine eigene Hardware hat?

Je nach Anforderung. Roboter Systeme, SPS, Hausautomatisierung bauen 
alle auf eigene Hardware auf. Teils sogar selbst entworfene Prozessoren.
Aber ist ja auch wurscht, jedes Projekt hat eigene Anforderungen.

BG

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.