Forum: Mikrocontroller und Digitale Elektronik Wozu braucht man Funktionspointer?


von Guido B. (guido-b)


Lesenswert?

Zum Glück wurde der LUNA-Thread geschlossen. Ein Argument von
c-hater beschäftigt mich aber doch: Es ist wohl für eine
Programmiersprache wichtig, dass diese über Krücken wie
Funktionspointer verfügt. Diese gibt es z.B. auch in Pascal als
funktionale Parameter.

Nur wozu braucht man die? Akademische Argumente kenne ich, in der
Praxis habe ich sie noch nie gebraucht. Mache ich was falsch ;-)?
Habt ihr Beispiele außerhalb des theoretischen Bereiches?

von (prx) A. K. (prx)


Lesenswert?


von Thorsten (Gast)


Lesenswert?

- Um einem Interrupt eine Funktion zuzuweisen
- Callback Funktionen
- ...

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Bei diesem Projekt habe ich zB nen Funktionspionter genutzt umd ne 
Zeichensatz austauschen zu können:
http://www.fritzler-avr.de/HP/ledscreen.php
Da sind momentan nur Großbuchstaben drinne und wenn noch Kleinbuchstaben 
dazukommen sollen muss ja die Umwandlungsfunktion getauscht werden.

Dabei handelt es sich um die get_seg16 in der seg16.c.
Da könnte dann zB im Betrieb der Zeichensatz gewechselt werden.

Ansonsten zB Interrupts, wenn man diese per Hand in die Interruptabelle 
einträgt.
In die Tabelle muss ja nen Pointer auf den Interrupthandler der eine 
Funktion ist.

von Kindergärtner (Gast)


Lesenswert?

Jumptables zum Beispiel, wenn man eine Liste aus 20 Funktionen hat zum 
Durchführen 20 verschiedener Aktionen, und man einen Integer hat der 
angibt welche Aktion durchgeführt werden soll, kann man die 
Funktionspointer in ein Array packen und mit dem Index die richtige 
finden & aufrufen.

Außerdem für callbacks, zB. um die Vergleichsoperation für qsort 
anzugeben. Oder z.B. bei der GUI-Programmierung gibt man der GUI-Library 
einen Funktionspointer damit sie eine Funktion im User-Code aufruft wenn 
der Benutzer einen Knopf gedrückt hat.

Google "Pascal funktionale Parameter" liefert diesen Thread, was genau 
meinst du damit...?

von Guido B. (guido-b)


Lesenswert?

Uihh, das ging ja fix. Danke für die Antworten.

Aber wir sind im Forum Mikrocontroller, nicht PC-
oder Betriebssystementwicklung. Braucht man sowas in
diesem Bereich wirklich?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Als ob auf so manchen ARM kein OS laufen würde und Interrupts hat man ja 
nun wirklich fast überall?

von Harry L. (mysth)


Lesenswert?

Guido B. schrieb:
> Braucht man sowas in
> diesem Bereich wirklich?

Ja!

von (prx) A. K. (prx)


Lesenswert?

Guido B. schrieb:
> Aber wir sind im Forum Mikrocontroller, nicht PC-
> oder Betriebssystementwicklung. Braucht man sowas in
> diesem Bereich wirklich?

Es stehen doch genug Beispiele oben, die auch auf µCs zutreffen. Noch 
nie ein Menusystem in µCs gesehen? Oder einen simplen Timer-Scheduler?

von Peter D. (peda)


Lesenswert?


von Guido B. (guido-b)


Lesenswert?

Martin Wende schrieb:
> Als ob auf so manchen ARM kein OS laufen würde und Interrupts hat man ja
> nun wirklich fast überall?

Ja, gut, aber von Linux sehe ich mal ab.

A. K. schrieb:
> Es stehen doch genug Beispiele oben, die auch auf µCs zutreffen. Noch
> nie ein Menusystem in µCs gesehen? Oder einen simplen Timer-Scheduler?

Auch schon selbst entwickelt, aber keine Funktionspointer hierfür
benötigt.

Peter Dannegger schrieb:
> Beitrag "Wartezeiten effektiv (Scheduler)"

Meine Programme warten nie, die gehen höchstens in den Sleep-Modus.

Ich bin noch nicht überzeugt. ;-)

von Kindergärtner (Gast)


Lesenswert?

Virtuelle Funktionen und abstrakte Interfaces verwenden intern 
Funktionspointer, und sind ein sehr beliebtes und mächtiges Werkzeug zur 
Abstrahierung und Trennung von Interface und Implementation, und damit 
Trennung von einzelnen Komponenten komplexer Systeme.

Beispiel: Verschiedene IO-Interfaces liefern Daten an, und verschiedene 
Programmkomponenten können diese entgegennehmen und unterschiedliche 
Aktionen vornehmen. Man kann für diese Komponenten (inkl. der 
IO-Treiber) nun abstrakte Interfaces definieren, sd. alle I/O-Interfaces 
von außen gleich aussehen ("es kommen bytes heraus") und man sie 
beliebig mit den weiterverarbeitenden Komponenten verbinden kann, und 
diese Bindung außerdem zur Laufzeit beliebig ändern kann.
Die Entscheidung, welcher Code ausgeführt wird in Anhängigkeit davon was 
momentan womit verbunden ist, wird mit einem Funktionspointer getroffen 
(intern).

von Harry L. (mysth)


Lesenswert?

Guido B. schrieb:
> Ich bin noch nicht überzeugt. ;-)

Warum sollen wir dich überzeugen?
Wenn man C kann, und effektiv nutzen will, kommt man früher oder später 
selber drauf, daß Funktionspointer ein äußerst mächtiges Werkzeug sein 
können.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Es geht hier ja wohl nicht darum was DU brauchst.
Die Frag war "wozu".

Und Fakt ist nunmal, dass Funktionspointer genutzt werden.
Schwer ist es zudem auch nicht.

Guido B. schrieb:
> Ja, gut, aber von Linux sehe ich mal ab.

Gibt ja nicht nur Linux.

von Kindergärtner (Gast)


Lesenswert?

Guido B. schrieb:
> Ja, gut, aber von Linux sehe ich mal ab.
Und die 1000 kleinen RTOS?

Guido B. schrieb:
> Auch schon selbst entwickelt, aber keine Funktionspointer hierfür
> benötigt.
Dadurch würde es aber modularer & wiederverwendbarer, da du den 
generischen Menücode komplett von dem Code trennen kannst, der die Liste 
der Menüpunkte und die durchzuführenden Aktionen definiert.

von Peter D. (peda)


Lesenswert?

Guido B. schrieb:
> Meine Programme warten nie, die gehen höchstens in den Sleep-Modus.

Lies den Beitrag doch erstmal durch, es geht um das nicht blockierende 
Warten.
Während Sleep kann die CPU ja nichts anderes machen.

von cppler (Gast)


Lesenswert?

Jede Klasse in C++ ist ein Funktionspointer, so werden die 
dereferenziert und damit sind wir beim Thema.
Wenn Du in einem Programm dynamisch Funktionen ändern können willst 
nimmst Du einen "Voidpointer" und benutzt den um die dazugehörige 
Funktion aufzurufen, problematisch können dabei Parameter sein aber in C 
kann man ja beliebige Parameter übergeben, was natürlich eine weitere 
schöne Fehlerquelle ist.
Und jetzt überlegen wir mal was der Funktionsname selber darstellt :-P

von Kindergärtner (Gast)


Lesenswert?

cppler schrieb:
> Jede Klasse in C++ ist ein Funktionspointer, so werden die
> dereferenziert und damit sind wir beim Thema.
Wie kann denn eine Klasse ein Funktionspointer sein, auf welche Funktion 
zeigt der denn?

cppler schrieb:
> was natürlich eine weitere
> schöne Fehlerquelle ist.
... die man zum Glück vermeiden kann!

von Guido B. (guido-b)


Lesenswert?

@ Kindergärtner:

Danke, jetzt wird es klarer. das macht also wirklich nur mit OOP
Sinn. Aber Pascal kann es ja auch??? Fakt ist, dass es sehr
trivial zu realisieren ist, das könnte jedem Compiler in ein
paar Stunden beigebracht werden.

Peter Dannegger schrieb:
> Lies den Beitrag doch erstmal durch, es geht um das nicht blockierende
> Warten.
> Während Sleep kann die CPU ja nichts anderes machen.

Sorry, Peter, ich habe nur die Anfangsbeschreibung gelesen, den Rest
nehme ich mir morgen vor.

Danke für die Erläuterungen.

von Kindergärtner (Gast)


Lesenswert?

Guido B. schrieb:
> Danke, jetzt wird es klarer. das macht also wirklich nur mit OOP
> Sinn.
Gar nicht, siehe qsort! Aber in Kombination mit OOP wird es erst richtig 
interessant, ja.
> Aber Pascal kann es ja auch???
Kann sein?
> Fakt ist, dass es sehr
> trivial zu realisieren ist, das könnte jedem Compiler in ein
> paar Stunden beigebracht werden.
Das kommt doch stark auf die Komplexität der Sprache und des Compilers 
an...

von Tom K. (ez81)


Lesenswert?

Praxis-Beispiel auf dem AVR ohne OOP:
Zu jedem Sensor ein struct, in dem ADC-Kanal und ein Funktionspointer 
auf die Funktion mit der Spannung/Messwert-Kennlinie für den Sensor 
stecken, der µC hat nur gemessen, umgerechnet und ausgegeben.

Die Alternative wäre eine switch-case-Orgie gewesen, mit Änderungen an 
zig verschiedenen Stellen, wenn sich die Sensorkonfiguration ändert. Die 
paar Byte verschwendeter RAM waren (wie fast immer) egal, dafür konnte 
man in ein paar Zeilen durch ein Array mit den erwähnten structs loopen 
und jeden Sensor gleich behandeln.

von (prx) A. K. (prx)


Lesenswert?

Guido B. schrieb:
> Ich bin noch nicht überzeugt. ;-)

Niemand zwingt dich dazu, sie zu verwenden. Du kannst Anwendungen auch 
für eine Turingmaschine schreiben, wenns dir behagt. ;-)

von Olaf (Gast)


Lesenswert?

> Aber wir sind im Forum Mikrocontroller, nicht PC-
> oder Betriebssystementwicklung.

Ich springe damit z.B aus meinen Bootloadern in den Anwendungscode. Wie 
machst du das?

Olaf

von Mr. X (Gast)


Lesenswert?

Guido B. schrieb:
> Aber Pascal kann es ja auch???

Hinter jedem Sprung in eine Ereignisbehandlung verbirgt sich ein 
Funktionspointer.

von Wolfgang H. (frickelkram)


Lesenswert?

Hi,

Guido B. schrieb:
> Martin Wende schrieb:
...
> Ich bin noch nicht überzeugt. ;-)

hier muss Dich ja auch keiner überzeugen. Prinzipiell kannst Du auch 
alles mit If-Then-Else oder Switch-Case Ketten machen, aber eleganter 
geht es halt oft mit Funktionspointern. Entscheide selbst ob Du die 
Hinweise annehmen möchtest.

Das Beispiel mit den Menüs finde ich da ziemlich gut. Eine universelle 
Bibliothek für LCD-Menüs ohne Funktionspointer wird recht umständlich zu 
programmieren.

von Wolfgang H. (frickelkram)


Lesenswert?

Bei vielen PIC Prozessoren kann man nicht direkt den Programmspeicher 
adressieren (Harvard Architektur). Wenn man Konstanten im 
Programmspeicher ablegen und nutzen möchte kann man zur Laufzeit des 
Programms auch nur über Call-Aufrufe da heran kommen. Das sind dann 
Funktionspointer, z.B direkt in Assembler ...
Wie ist das bei den AVRs, die nutzen ja auch die Harward Architektur? Da 
gibt es ja die Makros in pgmspace.h . Lesen die Makros die Werte der 
Konstanten auch über Calls?
Dann sind das auch Funktionspointer, auch wenn man es nicht sofort sehen 
kann.
Jede Programmiersprache die man auf diesen Prozessoren den 
Programmspeicher für Daten nutzt muss dann ja, wenn auch versteckt, 
Funktionspointer nutzen können.
Das Ganze macht natürlich nur für Arrays Sinn. Einfache Konstanten 
werden vom Compiler direkt als Werte in den finalen Maschinencode 
übersetzt.

von (prx) A. K. (prx)


Lesenswert?

Wolfgang Heinemann schrieb:
> Lesen die Makros die Werte der Konstanten auch über Calls?

Nein, das ist eine Besonderheit einiger PICs und liegt am fehlenden 
Ladebefehl, was wiederum mit der Befehlsbreite von 12/14 Bits zu tun 
hat. AVR hat den Befehl, PIC18 ebenso.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Wolfgang Heinemann schrieb:
> Guido B. schrieb:
>> Martin Wende schrieb:
> ...
>> Ich bin noch nicht überzeugt. ;-)

Bitte richtig zitieren, ich hab nix gegen Funktionspointer...

von Reinhard Kern (Gast)


Lesenswert?

Wolfgang Heinemann schrieb:
> Bei vielen PIC Prozessoren kann man nicht direkt den Programmspeicher
> adressieren (Harvard Architektur).

Das ergibt sich nicht zwingend aus der Harvard-Architektur. Natürlich 
kann es einen Prozessorbefehl dafür geben; dass der dann u.U. 12 bit 
oder 8 + 4 liefert ist eine Detailfrage. Aber in der Frühzeit der PICs 
hat halt jemand entschieden, dass man den Befehl nicht braucht oder dass 
er zuviel kostet. Das ist aber nicht die einzige Merkwürdigkeit, manches 
an den PICs ist nur historisch zu verstehen.

Auf Befehlsebene ist ein Funktionspointer eigentlich nur ein indirekter 
Sprung oder Call - springe zu der Adresse im Register Rx. Die 
Realisation in einer Hochsprache hat aber den grossen Vorteil der 
Typprüfung der Aufrufparameter, was man in Assembler selbst 
sicherstellen muss.

Gruss Reinhard

von Hubert (Gast)


Lesenswert?

Wozu braucht man Multiplikation? In der Praxis bin ich bisher immer mit 
Addition und Schleife ausgekommen. ;-)

von abc (Gast)


Lesenswert?

Ich vergleich mal Funktionspointer mit einem Interfacen aus der OO (mit 
genau einer Methode)

Dadurch lässt sich z.B. eine Sort Parameterisieren. ein mal solls 
aufsteigend sein, beim nächsten mal absteigend, beim nächsten mal nach 
laufzeit, einmal Strings, dann sinds Ints, dann negative Zahlen, ... Das 
ganze kann man über in der Funktion realisieren die man dem Sort beim 
Aufruf übergibt.

Das ganze ist folgende Vorteile:
- Der Sort ist generisch und kann damit wiederverwendet werden. Nur die 
Vergleichsfunktion ist neu anzupassen.
- Es spart Code da der Sort Code nur einmal je Programm existiert. Nur 
die Vergleichsfunktionen kommt für jeden unterschiedlichen Sort das dein 
Programm benötigt neu dazu.
- Testbarkeit, wenn dein Sort an sich mal funktioniert, und im neuen 
Programm nicht, dann liegt es mit sehr grosser warscheinlichkeit an der 
Vergleichsfunktion und nicht am Sort selber.
- Testbarkeit, Fehlerbereinigungen im Sort wirken sich auf jede in 
deinem Programm verwendeten Sort aus. du musst den Fix nicht an 10 
stellen nachziehen und ggf auch noch anpassen.

von Svenska (Gast)


Lesenswert?

Funktionspointer braucht man für Sprungtabellen. Compiler setzen 
Switch/Case (Zustandsautomaten!) auch gerne mit sowas um. Und wenn der 
Compiler das intern können muss (und sei es für die Optimierung), warum 
nicht auch gleich dem Programmierer anbieten?

von (prx) A. K. (prx)


Lesenswert?

Svenska schrieb:
> Funktionspointer braucht man für Sprungtabellen.

Dafür sind indirekte Sprünge in der Maschine nützlich, aber keine 
Funktionspointer in der Programmiersprache. In der Programmiersprache 
wird das implementiert, was nützlich ist und halbwegs ins Konzept der 
Sprache passt. Nicht alles, was zufällig irgendwie geht.

von (prx) A. K. (prx)


Lesenswert?

Wem Funktionszeiger zu rustikal sind, der kann sich ja mal mit Closures 
befassen. Die sind z.B. in C nicht zu finden, aber deutlich 
universeller: https://en.wikipedia.org/wiki/Closure_(computer_science)

von D. I. (Gast)


Lesenswert?

A. K. schrieb:
> Wem Funktionszeiger zu rustikal sind, der kann sich ja mal mit Closures
> befassen. Die sind z.B. in C nicht zu finden

Dafür in den gängigen dynamisch typisierten Skriptsprachen und anderen. 
Closures sind ein klasse Mittel wenn man weiß wie man sie sinnvoll 
nutzt.

von W.S. (Gast)


Lesenswert?

Guido B. schrieb:
> Nur wozu braucht man die? Akademische Argumente kenne ich, in der
> Praxis habe ich sie noch nie gebraucht. Mache ich was falsch ;-)?
> Habt ihr Beispiele außerhalb des theoretischen Bereiches?

Nö, wenn du sowas bislang nicht gebraucht hast, dann hast du damit nix 
falsch gemacht.

Es gibt aber ne Menge Anwendungen dafür. Ein Beispiel kannst du in der 
Lernbetty (Codesammlung) im dortigen Menüsystem nachlesen. Dort hab ich 
nämlich das Menüsystem so organisiert. Jedes Menu-Item hat 1..3 solche 
Pointer, z.B. "OnDraw()" - das ist sozusagen die zu Fuß aufgesetzte und 
fertig im ROM gelinkte Objektorientiertheit, die man ja ansonsten in C 
nicht hat. Ich bezweifle auch, daß sich sowas in C++ machen läßt: 
Objekte nebst Hierarchie ohne Heap im ROM.

Ansonsten kann man mit sowas auch ne nichtblockende prozedurale 
Funktionsweise (Statemaschine) in Systemen aufsetzen, die ansonsten rein 
ereignisgesteuert sind, ohne_ RTOS und _ohne jedesmal aus irgendeinem 
Status eine switch (..) Kaskade loszutreten.

W.S.

von test (Gast)


Lesenswert?

Der Effizienz wegen.

Wie würdest du zum Beispiel ein Menu implementieren?
1
flash struct menuelement{
2
   unsigned char zahlvor;
3
   unsigned char zahlnach;
4
   unsigned char zahllinks;
5
   unsigned char zahlrechts;
6
   void (*tastehoch) (void);
7
   void (*tasterunter) (void);
8
   void (*tastelinks) (void);
9
   void (*tasterechts) (void);   
10
   void (*menuPunktAnzeige)(void);
11
   char flash *anzeigeString;  
12
}
13
menu[]={
14
           /*00*/{ 1, 1, 0, 0,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"-----Menu-----"},
15
           /*01*/{ 0, 0, 0, 2,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"Kalibrieren"},
16
                         
17
           /*02*/{ 6, 3, 0, 7,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"BremsPoti"}, 
18
           /*03*/{ 2, 4, 0,11,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"GasPoti"},
19
           /*04*/{ 3, 5, 0,16,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"Batterie"},
20
           /*05*/{ 4, 6, 0,19,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"Motor"},   
21
           /*06*/{ 5, 2, 0, 1,menuHoch,menuRunter,nop,menuRechts,menuPunkt,"Zurück"}
22
        };
23
interrupt [EXT_INT2] void ext_int2_isr(void){
24
  if(tastenfrei){
25
        switch(PINB){
26
          case 0b11111010: menu[menuaktuell].tasterunter();break;                   
27
          case 0b11111001: menu[menuaktuell].tasterechts();break;                 
28
          case 0b11110011: menu[menuaktuell].tastehoch();  break;                 
29
          case 0b11101011: menu[menuaktuell].tastelinks(); break;          
30
          default:         tasteFalsch();break;               
31
        }   
32
        tastenfrei=0;
33
  }
34
}
35
...
36
37
    menu[menuaktuell].menuPunktAnzeige();

von Michael A. (micha54)


Lesenswert?

Hallo,

hat mal einer in die libc geschaut wie dort stdio implementiert ist ?
Speziell put und get im Filedescriptor sind Funktionspointer.

Gruß,
Michael

von (prx) A. K. (prx)


Lesenswert?

Michael Appelt schrieb:
> Speziell put und get im Filedescriptor sind Funktionspointer.

War(ist?) nicht immer so.

von W.S. (Gast)


Lesenswert?

test schrieb:
> case 0b11111001: menu[menuaktuell].tasterechts();break;

hihihi...
Dein Anliegen versteh ich schon, dennoch bist du damit zu kurz 
gesprungen.

hint: und wer kümmert sich um 'menuaktuell'?



W.S.

von Guido B. (guido-b)


Lesenswert?

O.k. danke, ich glaube jetzt habe ich es kapiert. Der Vorteil
resultiert aus der Kombination mit Tabellen über diese Pointer,
deren Indizes sich z.B. aus dem Zustand einer FSM oder auch
der Sensornummer ergeben, so dass nicht weiter unterschieden
werden muss.

Korrekt? Da muss ich mir mal Gedanken drüber machen.

von c-hater (Gast)


Lesenswert?

Guido B. schrieb:

> O.k. danke, ich glaube jetzt habe ich es kapiert. Der Vorteil
> resultiert aus der Kombination mit Tabellen über diese Pointer,

Das ist eine (sicher nicht unwichtige) Anwendung von Funktionspointern.

Es wurden im Thread auch andere genannt, z.B. die austauschbare 
Compare-Funktion für immer denselben Sortieralgorithmus. In dieser Art 
gibt es noch viele andere Anwendungen. Du kannst jede beliebige 
Algorithmensammlung aus jedem Bereich der Informatik durchgehen, fast 
immer findest du darin auch welche, für die es sinnvoll ist, "tief 
innen" liegende Teilfunktionen ersetzbar zu gestalten, um eben diesen 
Algorithmus zur Laufzeit leicht auf unterschiedliche Anwendungfälle 
anpassen zu können.

Parallel läuft z.B. gerade ein Thread von irgendsoeinem Loser, der 
Probleme damit hat, eine Bresenham-Linie mit variabler Strichstärke zu 
ziehen. Hätte die Pappnase innen im Bresenham einen Funktionspointer zum 
Aufruf einer PrintPen(x,y) vorgesehen, wäre der Drops sofort gelutscht. 
Eben diese Funktion müßte nämlich dann nur ausgetauscht werden...

> Da muss ich mir mal Gedanken drüber machen.

Nachdenken hat noch niemandem geschadet. Soviel ist mal sicher.

von Kindergärtner (Gast)


Lesenswert?

A. K. schrieb:
> Die sind z.B. in C nicht zu finden,
Aber dafür in C++11 :-)
1
#include <iostream>
2
 
3
template <typename F>
4
void range(int count, F f) {
5
    for (int i = 0; i < count; i++)
6
        f(i);
7
}
8
 
9
int main () {
10
    int x = 0;
11
    range(27, [&](int i) {
12
       x += i; 
13
    });
14
    std::cout << x;
15
}
Ganz einfaches Beispiel, war gerade zu faul das für einen 
Sortieralgorithmus zu machen :)

W.S. schrieb:
> Ich bezweifle auch, daß sich sowas in C++ machen läßt:
> Objekte nebst Hierarchie ohne Heap im ROM.
Selbstverständlich geht das, einfach die Instanz als "const" angeben. Du 
kannst sogar die Initialisierungs-werte zur Compilezeit berechnen lassen 
in einer Art eingebauten funktional-Version von C++, durch die 
Verwendung von constexpr. C kann das nicht...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

c-hater schrieb:
> Parallel läuft z.B. gerade ein Thread von irgendsoeinem Loser (...)
> Hätte die Pappnase (...)

> Nachdenken hat noch niemandem geschadet. Soviel ist mal sicher.


Dann fang Du mal an über Umgangsformen nachzudenken. Mit diesem Deinem 
Beitrag jedenfalls bist Du in Sachen Umgangsformen definitiv ein 
Loser.

von Kindergärtner (Gast)


Lesenswert?

W.S. schrieb:
> Ich bezweifle auch, daß sich sowas in C++ machen läßt:
> Objekte nebst Hierarchie ohne Heap im ROM.
Hier noch ein kleines Beispiel dazu: http://ideone.com/IsG0UD

Es wird eine Tabelle aus integern und deren Fakultätszahlen im ROM 
abgelegt. Diese besteht aus einer FacTable die die einzelnen 
Zahl-Fakultät -Kombinationen in Form von FacTable-Entry -Instanzen 
enthält. Die Fakultätszahlen werden automatisch vom Compiler berechnet 
und das Ergebnis landet als ein Block im ROM. In der main() folgt eine 
Test-Ausgabe.
Meines Wissens geht so etwas in C nicht ohne externe Code-Generatoren 
(hässlich, fehleranfällig, unflexibel).

Fakultätszahlen sind jetzt ein bisschen akademisch aber das ganze lässt 
sich auch wunderbar für echte Anwendungen einsetzen.

von Thomas E. (thomase)


Lesenswert?

Rufus Τ. Firefly schrieb:
> c-hater schrieb:
>> Parallel läuft z.B. gerade ein Thread von irgendsoeinem Loser (...)
>> Hätte die Pappnase (...)
>
>> Nachdenken hat noch niemandem geschadet. Soviel ist mal sicher.
>
>
> Dann fang Du mal an über Umgangsformen nachzudenken. Mit diesem Deinem
> Beitrag jedenfalls bist Du in Sachen Umgangsformen definitiv ein
> Loser.
Guck mal auf die Uhrzeit, wann er den Beitrag geschrieben hat. Je später 
der Abend, desto rüder der Ton. Kennt man doch schon.

http://www.youtube.com/watch?v=mW08rCpM8lo

mfg.

von Malte S. (maltest)


Lesenswert?

Kindergärtner schrieb:
> Fakultätszahlen sind jetzt ein bisschen akademisch aber das ganze lässt
> sich auch wunderbar für echte Anwendungen einsetzen.

Ich bau mir nach ähnlichem Prinzip sin/cos-Tabellen, ist aber noch zu 
dreckig für die Öffentlichkeit.

PS: Vorteil: Datentyp, Definitions- und Wertebereich lassen sich als 
Template-Parameter angeben. Compiler macht den Rest. Bis ca. 4096 
Schritte pro 360 Grad geht das mit dem 16bit double beim AVR prima per 
Taylorreihe in constexpr.

von W.S. (Gast)


Lesenswert?

Kindergärtner schrieb:
> Selbstverständlich geht das, einfach...

nanana, nimm mal den Mund nicht voller als du schlucken kannst. Ich 
schrieb von einem Menü-System im ROM. Ich hatte das damals für die 
Lernbetty außerhalb erzeugt - zuerst mit Script, dann per 
Pascal-Programm (sic!)

Also, ich nehme dich mal beim Wort: Die Lernbetty ist in der 
Codesammlung ja immer noch zu finden, man kann dazu sowohl Keil als auch 
Yagarto benutzen und es wäre schon ein guter und frischer Wind darin, 
wenn du das Menü-System der Lernbetty mal übungshalber auf C++ umstellst 
- aber ohne den RAM zuzumüllen, denn der soll ja so gut es geht für die 
Apps freigehalten werden.

Mach mal. (ist mein voller Ernst)

W.S.

von Kindergärtner (Gast)


Lesenswert?

W.S. schrieb:
> nanana, nimm mal den Mund nicht voller als du schlucken kannst.
Sagt der, der solchen Code verbricht:
1
#define RCST  const struct TMenuItem // Globales 4-buchstabiges Makro...
2
#define   cl_white      0   // warum nicht einfach "const"
3
#define   cl_ltgr       1   // warum keine Klammern?
4
#define   cl_dkgr       2
5
#define   cl_black      3
6
extern void Betty_Uhrzeit_OnEvent (RCST *self, word *aEvent); // unnötiges "extern", englisch & deutsch in EINEM Bezeichner...
7
8
/* semantisch: diese konventionen sind die des WinAPI, auf ARM ist ein "word" 32bit,
9
ein halfword 16bit und ein dword 64bit. Dein dword ist 4x so groß wie dein word.
10
technisch: noch nie von typedef, von <stdint.h>, von <stdbool.h> gehört??? */
11
#define  word      unsigned short int
12
#define  byte      unsigned char
13
#define  dword     unsigned long
14
#define  bool      unsigned char
dazu mehrfache Definition derselben Datenstrukturen etc. Hoffentlich 
bezieht sich das *Lern*betty nicht auf "C lernen".

Und ja, derartiges funktioniert auch in C++ komplett im ROM. 
Minimalbeispiel hier: http://ideone.com/Xfo20K
Die MenuItem Klasse enthält über ihre vtable die Funktionspointer zu den 
Behandlungsmethoden, die abgeleiteten MyMenuItem1,2 implementieren dann 
konkrete Funktionen die auf die Ereignisse reagieren. Da es dem 
OOP-Prinzip ein wenig zuwiderläuft Interface und Daten 
zusammenzuspeichern, musste ich ein bisschen Pointermagic betreiben, 
funktioniert aber und ist dank static_assert auch sicher. Über die 
Konstante "myMainMenu" wird dann das ganze Menü zusammengebaut. Die 
Beispiel-main gibt einfach nur alle Menüeinträge am stdout aus und ruft 
2 Eventhandler auf. Da "myMainMenu" als  "constexpr const" markiert ist, 
ist der Compiler gezwungen das Menü komplett im ROM abzulegen. Bei 
diesem Programm landet außer den temporären Variablen in der main() 
nichts im RAM.
Durch den Array-artigen Ansatz spart man sich pro Menüeintrag einen 
Pointer im Vergleich zu deinem linked list-Ansatz. Auf jedes MenuItem 
folgen seine Sub-MenuItems, deren Anzahl dem Eltern-MenuItem bekannt 
ist. So wird effizient eine rekursive Objektstruktur aufgebaut. Ich 
hätte noch etwas Wrappercode schreiben können um auch die 
Initialisierung rekursiv&elegant zu machen (s.d. man nicht selbst mit 
den subitem-Anzahlen rumhampeln muss), aber das würde es jetzt etwas 
unnötig verkomplizieren.

W.S. schrieb:
> wenn du das Menü-System der Lernbetty mal übungshalber auf C++ umstellst
Klar, wenn du das sagst... Ich glaub ich habe bessere "Übungen".

W.S. schrieb:
> aber ohne den RAM zuzumüllen
Wer hat eigentlich den Mythos in die Welt gesetzt, C++ würde irgendwas 
zumüllen? Das kann man eigentlich eher von C und der ganzen 
void-Pointerei sagen.

W.S. schrieb:
> Yagarto
... kommt nicht mit FPU's klar, der gcc-arm-embedded ist da besser.

von typecast (Gast)


Lesenswert?

Thorsten schrieb:
> - Um einem Interrupt eine Funktion zuzuweisen
> - Callback Funktionen
> - ...

Genau deswegen. Vor allem wenn man Sachen modular aufbauen will.

von W.S. (Gast)


Lesenswert?

Kindergärtner schrieb:
> Sagt der, der solchen Code verbricht:...

Herzlich gelacht.

ach, Junge, herumlabern kann jeder, es besser machen nur wenige.
Du regst dich auf über "Denglisch"? oder über #define ? oder über einen 
griffigen RCST? oder über word, dword, bool und Konsorten? Die hat es 
schon gegeben, als ARM noch in den Kinderschuhen steckte.

Da hast du noch was übersehen: ein GOTO in main. Furrrchtbar. Und seit 
wann ist "extern" derart überflüssig, daß man es nicht verwenden sollte?

Wenn ich mir hingegen das anschaue:
int main () {
        for (auto& item : myMainMenu) {
                std::cout << item.m_label << std::endl;
        }
        myMainMenu [0].onDraw ();
        myMainMenu [1].onKey ();
}

dann ist mir klar, daß du wahrscheinlich überhaupt nix verstanden hast 
und bloß wie Beckmesser in Nürnberg die Anzahl der Pointer zählst.

Und zum Schluß, den Satz "Ich glaub ich habe bessere "Übungen"" halte 
ich für nen mißlungenen Versuch des Rückzugs. Du kannst es einfach 
nicht, möchtest dich aber dennoch großartig fühlen - das ist es. Kann 
ich verstehen, wer von uns möchte denn nicht insgeheim auch mal sich 
großartig fühlen... Also: entweder wirklich mal was Besseres für die 
Lernbetty vorlegen oder einfach sich in etwas mehr Bescheidenheit 
ergehen.

So, Schluß für heute, den Rest Malbec (Argentinien, 2011) trinke ich 
jetzt aus und dann Nachtruhe. Wünsch ich ebenfalls allen Mitlesesern.

W.S.

von Karl H. (kbuchegg)


Lesenswert?

Kindergärtner schrieb:

> Und ja, derartiges funktioniert auch in C++ komplett im ROM.
> Minimalbeispiel hier: http://ideone.com/Xfo20K

ziemlich interessant.
Wenn ich demnächst mehr Zeit habe, muss ich das mal im Detail studieren 
und mich mit Templates mal etwas weiterbilden. :-) Meine schwache Stelle 
:-)

von Kindergärtner (Gast)


Lesenswert?

W.S. schrieb:
> Herzlich gelacht.
Dito.
> ach, Junge, herumlabern kann jeder, es besser machen nur wenige.
Ich habe dir ja gezeigt wie es besser geht.
> Du regst dich auf über "Denglisch"? oder über #define ? oder über einen
> griffigen RCST? oder über word, dword, bool und Konsorten? Die hat es
> schon gegeben, als ARM noch in den Kinderschuhen steckte.
Das kann sein, aber besser wirds dadurch nicht. Tatsächlich generiert 
solch altes Zeug auch heute noch eine Menge unnötiger Probleme.
> Da hast du noch was übersehen: ein GOTO in main. Furrrchtbar.
Ich hatte nur ganz kurz einige Stellen überflogen, ich bin mir sicher es 
gibt noch eine ganze Reihe lustiger vorbildlicher Dinge in deinem Code.
> Und seit
> wann ist "extern" derart überflüssig, daß man es nicht verwenden sollte?
C99 oder sogar schon früher. Bei Variablen braucht man es, bei 
Funktionen ist es überflüsslig.

> Wenn ich mir hingegen das anschaue:
> int main () {
>         for (auto& item : myMainMenu) {
>                 std::cout << item.m_label << std::endl;
>         }
>         myMainMenu [0].onDraw ();
>         myMainMenu [1].onKey ();
> }
>
> dann ist mir klar, daß du wahrscheinlich überhaupt nix verstanden hast
> und bloß wie Beckmesser in Nürnberg die Anzahl der Pointer zählst.
Dann erleuchte mich, was für Probleme gibt es hier deinem Verständnis 
nach? Das std::out Zeug läuft natürlich nur am PC (oder wo man stdout 
hat), aber zur Demonstration ist das praktisch. Die Iteration ist das 
elegante, sichere & abstrakte C++ Äquivalent zur klassischen 
C-Pointer-Inkrement-Loop, und genau so effizient (im Endeffekt wird nur 
ein Pointer auf den Anfang des Arrays gesetzt und der solange 
hochgezählt bis man am Ende angekomemn ist).

> Und zum Schluß, den Satz "Ich glaub ich habe bessere "Übungen"" halte
> ich für nen mißlungenen Versuch des Rückzugs.
Oder lediglich als Hinweis das ich nicht den ganzen Tag rumsitze und auf 
Vorschläge von dir warte.
> Du kannst es einfach
> nicht, möchtest dich aber dennoch großartig fühlen
Ich kann - und mache! - noch viel bessere Sachen, und deswegen fühl ich 
mich auch ganz toll.
> großartig fühlen... Also: entweder wirklich mal was Besseres für die
> Lernbetty vorlegen oder einfach sich in etwas mehr Bescheidenheit
> ergehen.
Ist in Arbeit, dauert nur noch ein bisschen. Wird dann auch nicht unter 
diesem Nick veröffentlicht :-P

Karl Heinz Buchegger schrieb:
> Wenn ich demnächst mehr Zeit habe, muss ich das mal im Detail studieren
> und mich mit Templates mal etwas weiterbilden. :-) Meine schwache Stelle
Sehr gut :-) Templates (und constexpr) sind sehr mächtig und besonders 
für Mikrocontroller interessant, da man so viel Strukturierung&Rechnung 
zur Compilezeit durchführen kann. Bei ungeschickter Verwendung kann man 
eventuell mehr Code als beabsichtigt generieren, daher muss man wissen 
was man tut... :-)

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.