Makro Funktionen avr-gcc

OP #6419797
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.
Gast #6419839
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.
Gast #6420003
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.
Gast #6420013
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.
Gast #6420115
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.
OP #6420143
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.
Gast #6420161
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.
OP #6420210
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.
Gast #6420213
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?
Gast #6420590
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?
Gast #6420604
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.
Gast #6420659
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.
OP #6420713
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
}
Gast #6420730
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren