Forum: Mikrocontroller und Digitale Elektronik Makro Funktionen avr-gcc


von Philipp K. (philipp_k59)


Lesenswert?

ich habe 5 Arrays die ich im Moment noch als Test vor dem (Setup) 
Mainloop mit berechneten Werten auffülle, teils sind das Bitschieberei 
oder auch einige For-Schleifen aus den Arduino "Defines".

Ich habe mich jetzt gefragt ob das so optimiert wird das es vorweg 
berechnet wird weil es ja dann Fest ist oder ich das ganze in Makros und 
Defines umdefinieren muss.

Gibt es dazu eine gute Seite die das mit den Makros einigermaßen 
beschreibt? In den Artikeln die ich hier gefunden habe sind keine 
Beispiele bzw. Speziell ASM Makros behandelt.

von Oliver S. (oliverso)


Lesenswert?

Zeig doch einfach deinen Code. Deine Erzählungen darüber helfen nicht 
weiter.

Oliver

von Stefan F. (Gast)


Lesenswert?

Makros sind Textersetzungen, die vor dem Compilieren angewendet werden. 
Der GCC hat eine Kommandozeilenoptionen, mit dem du den modifizierten 
Quelltext ausgeben kannst.

Wie gut der Compiler deinen Code optimiert, hängt ganz stark vom 
Compiler, seinen Optionen und natürlich dem aktuellen Quelltext ab. Alle 
drei Infos solltest du ganz schnell nachreichen, damit das hier nicht zu 
einer endlosen Diskussion ohne Praxisbezug ausartet, wo sich jeder 
einbildet, besser zu wissen, was du gerade machst oder brauchst.

von Sagittarius (Gast)


Lesenswert?

Philipp K. schrieb:
> Ich habe mich jetzt gefragt ob das so optimiert wird das es vorweg
> berechnet wird weil es ja dann Fest ist oder ich das ganze in Makros und
> Defines umdefinieren muss.

Die Macros sind Textersetzungen und haben mit der Compileroptimierung 
eigentlich nichts zu tun.

Wenn du z.B. sowas definierst:
1
#define x (2+3)
2
3
printf("%d\n", x);

dann ersetzt der Präprozessor dieses x durch (2+3) (diese Summe wird 
nicht mal ausgerechnet).

So steht da einfach nur:
1
printf("%d\n", (2+3));

Das kannst du mit

gcc -E mein_file.c

sehen.

Für die Optimierung ist der Compiler zuständig.

von Einer K. (Gast)


Lesenswert?

Philipp K. schrieb:
> Gibt es dazu eine gute Seite die das mit den Makros einigermaßen
> beschreibt? In den Artikeln die ich hier gefunden habe sind keine
> Beispiele bzw. Speziell ASM Makros behandelt.

Offensichtlich arbeitest du mit Arduino.
Das steckt tief in der C++ Welt, und diese hat Makros zum Teil unnötig 
gemacht. Zumindest auch den Teil, welcher Funktionen abbilden will.

Es wird also vermutlich bessere Alternativen geben, als 
Makro(funktionen).

Leider hast du vergessen zu sagen, was du erreichen willst.

von A. S. (Gast)


Lesenswert?

Philipp K. schrieb:
> ich habe 5 Arrays die ich im Moment noch als Test vor dem (Setup)
> Mainloop mit berechneten Werten auffülle, teils sind das Bitschieberei
> oder auch einige For-Schleifen aus den Arduino "Defines".
>
> Ich habe mich jetzt gefragt ob das so optimiert wird das es vorweg
> berechnet wird weil es ja dann Fest ist oder ich das ganze in Makros und
> Defines umdefinieren muss.

es ist nicht ganz klar, was du in defines packen willst:
Die Werte, mit denen die Arrays gefüllt werden? Oder willst Du die 
Arrays durch #defines ersetzen?

je nach Aufgabe und Randbedingung kann jede der 3 Varianten besser sein. 
Wenn das array größer ist als der Code zu dessen Füllung, und die 
Startup-Zeit nicht stört, kann Deine Version die beste sein.

Mach mal ein Beispiel.

von Ganz Klar (Gast)


Lesenswert?

Philipp K. schrieb:
> Ich habe mich jetzt gefragt ob das so optimiert wird das es vorweg
> berechnet wird weil es ja dann Fest ist oder ich das ganze in Makros und
> Defines umdefinieren muss.

Zeig doch mal ein Minimalbeispiel.
Aus den Wirren kann man nur raten.

von Philipp K. (philipp_k59)


Lesenswert?

Danke für die Antworten, da man ja bei Arduino diese freien 
Pinzuordnungen hat (D1,A1,etc) wollte ich mir eine Funktion 
bereitstellen die zum Beispiel über einen Array den man mit Pins füllt 
mehrere Ports mit kleinstem Overhead setzt.

Normalerweise benutzt man ja digitalWrite(pin, high) da wird nur im 
zugehörigen port das eine bit mit Overhead gesetzt.

Die Funktion benutzt dann eigentlich nur Variablen die vor dem 
Kompilieren bekannt sein könnten. Ich habe das schonmal in Serial fast 
fertig, da wird mir eine funktion zum reinkopieren als Text ausgegeben.

 Kann ich mal posten wenn fertig.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Ich verstehe dich nicht...

Möchtest du die Arduino Pinnummeriereung beibehalten?
Aber diese nicht zur Laufzeit aufdröseln, sondern zur Compilezeit.
Und dennoch die Pins in einem veränderlichen Array halten.

Wie dir Makros dabei helfen sollen, kann ich leider nicht erkennen.

von Philipp K. (philipp_k59)


Lesenswert?

okay, vielleicht anders erklärt.. ich bereite im Setup mehrere Arrays 
vor und habe mich dann gefragt ob das so optimiert wird das letzten 
endes nur die Arrays im Maschinencode übrig  bleiben weil alle 
zuständigen Werte in anderen Arrays und Variablen vorher bekannt sind.

Meine Idee war dann mit Makros könnte man das dann quasi erzwingen.

von Einer K. (Gast)


Lesenswert?

Philipp K. schrieb:
> Meine Idee war dann mit Makros könnte man das dann quasi erzwingen.
Makros erzwingen nix.
Das sind einfache Textersetzungen.


Mir scheint du suchst constexpr.
Das ist sozusagen die Typesichere Variante und man bekommt min. eine 
Warnung, wenn es nicht zur Compilezeit aufgelöst wird.

Aber warum in Setup füllen?

von Ganz Klar (Gast)


Lesenswert?

Und warum nicht einfach bei Deklaration schon richtig befüllen statt in 
der init, wenn es zur Compilezeit schon bekannt ist?
Dann "bleibt nur das Array". Der Lesbarkeit wegen machen hier Makros 
dann schon Sinn, aber mit Optimierung hat das nichts zu tun.

Auf der andern Seite optimiert man da nur wenig weg, oder ist die init 
so zeit- bzw. ressourcenkritisch?

von Philipp K. (philipp_k59)


Lesenswert?

Das Ding ist halt ich muss aus mehreren Arrays einen bauen, mit zb. for 
Schleifen..

Jetzt möchte ich die QuellArrays nicht mit einkompiliert haben.

Klar kann ich schnell eine exe zaubern die mir das eben vorbereitet, im 
Code wäre es besser.

von Einer K. (Gast)


Lesenswert?

Ganz Klar schrieb:
> Der Lesbarkeit wegen machen hier Makros dann schon Sinn,
Wenn nix anderes geht....
Aber solange es bessere Alternativen gibt.
Wie schon gesagt, constexpr Ausdrücke, oder Funktionen, haben hier 
deutliche Vorteile, bei gleich guter Lesbarkeit.


Ganz Klar schrieb:
> aber mit Optimierung hat das nichts zu tun.
Ja!
Da sind Makros weder förderlich, noch hemmend.

Auch schient mir hier nicht die Optimierung als ganzes gemeint zu sein, 
sondern nur der Teilbereich "Ausführung zur Compilezeit"
Ist dem so?

Philipp K. schrieb:
> Das Ding ist halt ich muss aus mehreren Arrays einen bauen, mit zb. for
> Schleifen..
Zeige doch endlich mal ein Beispiel.

von Ganz Klar (Gast)


Lesenswert?

Philipp K. schrieb:
> Das Ding ist halt ich muss aus mehreren Arrays einen bauen, mit zb. for
> Schleifen..
>...

Wo ist das Problem?

Das lässt sich doch bestimmt auch mit einem kleinen Python o. ä. schnell 
generieren.

von Ganz Klar (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Zeige doch endlich mal ein Beispiel

Jo, das macht es einfacher.

von Einer K. (Gast)


Lesenswert?

Habe das mal für einen Arduino UNO durchgespielt
Verwendet wird ein GCC 9.2 mit gnu++17
1
constexpr unsigned arraySize {3};
2
3
using MeinArray = int[arraySize];
4
5
constexpr MeinArray a {1,2,3};
6
constexpr MeinArray b {4,5,6};
7
8
struct MeinContainer
9
{
10
  MeinArray array;
11
};
12
13
constexpr MeinContainer fillContainer()
14
{
15
  MeinContainer c {{0}};
16
  for(unsigned i = 0; i < arraySize; i++)
17
  {
18
    c.array[i] = a[i] + b[i] + i; // Beispiel für eine beliebige Berechnung
19
  }
20
  return c;
21
}
22
23
void setup() 
24
{
25
  constexpr MeinContainer c {fillContainer()};
26
27
  for(unsigned i = 0; i < arraySize; i++)
28
  {
29
    PORTB = c.array[i]; // Ausgabe
30
  }
31
}
32
33
void loop() 
34
{
35
36
}


--

Und dieses bleibt von der Ausgabeschleife im Compilat übrig
1
  for(unsigned i = 0; i < arraySize; i++)
2
  {
3
    PORTB = c.array[i]; // Ausgabe
4
 1a6:  85 e0         ldi  r24, 0x05  ; 5
5
 1a8:  85 b9         out  0x05, r24  ; 5
6
 1aa:  88 e0         ldi  r24, 0x08  ; 8
7
 1ac:  85 b9         out  0x05, r24  ; 5
8
 1ae:  8b e0         ldi  r24, 0x0B  ; 11
9
 1b0:  85 b9         out  0x05, r24  ; 5
Die Arrays verschwinden vollständig.

von Ganz Klar (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> for(unsigned i = 0; i < arraySize; i++)
>   {
>     PORTB = c.array[i]; // Ausgabe
>   }

Das ist fragwürdig, da PORTB immer überschrieben wird und am Ende der 
init der letzte Wert aus array[arraySize-1] in PORTB steht...

von Philipp K. (philipp_k59)


Lesenswert?

constexpr hört sich gut an, da muss ich nochmal nachlesen, irgendwie war 
ich da auch schon vorbeigekommen.

Okay, mal ein kleines Beispiel auf das wesentliche beschnitten..
seven_segment_digits soll nicht miteinkompiliert werden..

Wenn ich das in Python machen will habe ich das schon in irgendwas 
anderem fertig gemacht bevor ich das Tutorial aufgerufen habe :D
1
uint8_t seven_segment_digits[10][7] = {
2
  { 1, 1, 1, 1, 1, 1, 0 }, // display '0'
3
  { 0, 1, 1, 0, 0, 0, 0 }, // display '1'
4
  { 1, 1, 0, 1, 1, 0, 1 }, // display '2'
5
  { 1, 1, 1, 1, 0, 0, 1 }, // display '3'
6
  { 0, 1, 1, 0, 0, 1, 1 }, // display '4'
7
  { 1, 0, 1, 1, 0, 1, 1 }, // display '5'
8
  { 1, 0, 1, 1, 1, 1, 1 }, // display '6'
9
  { 1, 1, 1, 0, 0, 0, 0 }, // display '7'
10
  { 1, 1, 1, 1, 1, 1, 1 }, // display '8'
11
  { 1, 1, 1, 0, 0, 1, 1 } // display '9'
12
};
13
14
int segmentPins[] = {A0, 7 , A3, A4, A5 , A1 , A2}; // PC0-5 PD7
15
16
unsigned char seg_codeB[10];
17
unsigned char seg_codeC[10];
18
unsigned char seg_codeD[10];
19
uint8_t BMask = 0;
20
uint8_t CMask = 0;
21
uint8_t DMask = 0;
22
23
void setup() {
24
  for (int i = 0; i < 10; i++)
25
    for (int c = 0; c < 7; c++) {
26
      if (seven_segment_digits[i][c] == 1) {
27
        uint8_t bit = 0;
28
        uint8_t pin = segmentPins[c];
29
        bit = digitalPinToBitMask(segmentPins[c]);
30
              if  (pin < 8) { DMask |= bit; if (seven_segment_digits[i][c] == 1) seg_codeD[i] |= bit;
31
        } 
32
        else  if  (pin < 14){ BMask |= bit; if (seven_segment_digits[i][c] == 1) seg_codeB[i] |= bit;
33
        } 
34
        else if   (pin > 13){ CMask |= bit; if (seven_segment_digits[i][c] == 1) seg_codeC[i] |= bit;
35
        }
36
      }
37
    }
38
        
39
      }
40
    
41
42
43
void setnum(uint8_t num) {
44
  uint8_t oldSREG = SREG;
45
  cli();
46
47
  PORTB |= (seg_codeB[num] & BMask);
48
  PORTC |= (seg_codeC[num] & CMask);
49
  PORTD |= (seg_codeD[num] & DMask);
50
  SREG = oldSREG;
51
}

von Einer K. (Gast)


Lesenswert?

Ganz Klar schrieb:
> Das ist fragwürdig, da PORTB immer überschrieben wird und am Ende der
> init der letzte Wert aus array[arraySize-1] in PORTB steht...
Es ist doch nur eine Beispiel Ausgabe.
Ein weiterer Sinn ist nicht beabsichtigt.
Nur um zu zeigen, dass die Arrays vollständig eliminiert werden und auch 
die Initialisierungsfunktion, mitsamt ihrer Schleife.

von Philipp K. (philipp_k59)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ein weiterer Sinn ist nicht beabsichtigt.

Okay danke, leuchtet jetzt ein mit dem constexpr.

von Philipp K. (philipp_k59)


Lesenswert?

Arduino Fanboy D. schrieb:
> Habe das mal für einen Arduino UNO durchgespielt

Nochmal Danke, diese Antwort habe ich irgendwie überlesen :-) .. ist mir 
jetzt nach Zig Tagen mit Templates und constexpr wenigstens schlüssig 
:)

von Einer K. (Gast)


Lesenswert?

Fein!

von Konstantin Qualle (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Die Arrays verschwinden vollständig.

Da stellt sich mir doch direkt die Frage nach dem Sinn Deiner Arrays, 
wenn sie vom Compiler einfach ignoriert werden.

Vielleicht solltest Du Dein Konstrukt mal mit Leben füllen und dann 
nochmal den Compiler fragen.

von Einer K. (Gast)


Lesenswert?

Konstantin Qualle schrieb:
> wenn sie vom Compiler einfach ignoriert werden.
Werden sie nicht.

Konstantin Qualle schrieb:
> Vielleicht solltest Du Dein Konstrukt mal mit Leben füllen und dann
> nochmal den Compiler fragen.
Vielleicht solltest du mal C++ lernen.

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.