Forum: Compiler & IDEs gcc/c++: Compilezeit-Array für progmem erstellen lassen


von Matho (Gast)


Lesenswert?

Hallo nochmal,
könnte etwas redundant sein, aber eigentlich nicht:
Ich habe gerade diese Frage im PC-Programmierungs-Forum gestellt:
Beitrag "c++: Lookup-Table Inhalt zur Compilezeit erstellen"

Quasi der allgemeine Fall, aber ich frage mich auch, ob es einen 
Spezialfall für µCs gibt. Ich habe nämlich ein wenig das Gefühl, dass 
embedded-gcc etwas anders arbeitet. Z.B. macht es (oft) keinen 
Unterschied, ob ich pass-by-value, oder pass-by-reference mache. Und 
einen this-Zeiger habe ich im asm auch noch nicht entdecken können..

Ich möchte gerne eine progmem-array erstellen, wobei:
1
array[i] = fkt(i,Size); //Size:Template-Parameter, i:Index

Bislang müsste ich für ene bestimmte 'Size' außerhalb ein Array 
berechnen und die Werte dann manuell im Code einfügen. Schön ist das 
nicht.

Hat jemand für diesen Fall eine Idee?
MfG
Matho

: Verschoben durch User
von Einer K. (Gast)


Lesenswert?

Ich habe Schwierigkeiten deine Frage zu verstehen, u.A. da ich einige 
deiner Annahmen nicht teile!

Matho schrieb:
> Z.B. macht es (oft) keinen
> Unterschied, ob ich pass-by-value, oder pass-by-reference mache.
Hier wüsste ich nicht, wie sich der AVR-GCC vom PC-GCC unterscheidet.
Denn C++ ist C++.

Matho schrieb:
> Und
> einen this-Zeiger habe ich im asm auch noch nicht entdecken können..
Tja...
Sowas gibts in Assembler auch nicht.
Und im Gcc Kompilat wird er nach Möglichkeit weg optimiert. z.B. nur 
einmal in einem Registerpaar gesetzt und dann stundenlang verwendet.

Matho schrieb:
> Ich möchte gerne eine progmem-array erstellen, wobei:array[i] =
> fkt(i,Size); //Size:Template-Parameter, i:Index
>
> Bislang müsste ich für ene bestimmte 'Size' außerhalb ein Array
> berechnen und die Werte dann manuell im Code einfügen. Schön ist das
> nicht.
Das verstehe ich überhaupt nicht.
Das ist auch kein testbarer Code.

Ich sehe noch nicht mal ein Template.

von Matho (Gast)


Lesenswert?

>Hier wüsste ich nicht, wie sich der AVR-GCC vom PC-GCC unterscheidet.
>Denn C++ ist C++.

Als bestes Beispiel würden mir viellicht progmem-arrays einfallen, da es 
die so auf dem PC nicht gibt.

>Sowas gibts in Assembler auch nicht.
Ich habe generell das gefühl, dass für µC mehr 'geinlined', optimiert 
und verboten wird.. Irgendwas war da doch auch z.B. mit virtuellen 
Methoden!?

>Das verstehe ich überhaupt nicht.
>Das ist auch kein testbarer Code.
Testbaren Code hätte ich auch gerne.
Ganz konkret möchte ich ein array im PROGMEM vom Compiler füllen lassen.
Mit etwas Pseudocode unabhängig von Templates o.Ä.:
1
const int Size = 123;
2
const int PROGMEM array[Size];
3
for(int i = 0; i<Size; ++i) array[i] = sin(i/Size*2*PI);

von Dr. Sommer (Gast)


Lesenswert?

Matho schrieb:
> Ich habe generell das gefühl, dass für µC mehr 'geinlined', optimiert
> und verboten wird..

Nö. Das macht der GCC beim PC ganz genauso. "Verboten" ist kaum was, nur 
manches braucht zu viel Speicher für die meisten µC. Dinge wie fopen() 
können nur funktionieren wenn man die entsprechenden Syscalls selbst 
nachbaut.

Matho schrieb:
> Irgendwas war da doch auch z.B. mit virtuellen
> Methoden!?
Die gehen ganz genau wie am PC. Man sollte nur die Funktion 
__cxa_pure_virtual überschreiben, weil die von der newlib zu viel 
Speicher braucht.

Der "this"-Pointer wirkt einfach wie ein 0. Parameter und wird z.B. bei 
arm in r0 übergeben.

von Einer K. (Gast)


Lesenswert?

Matho schrieb:
>>Hier wüsste ich nicht, wie sich der AVR-GCC vom PC-GCC unterscheidet.
>>Denn C++ ist C++.
>
> Als bestes Beispiel würden mir viellicht progmem-arrays einfallen, da es
> die so auf dem PC nicht gibt.
Ne, ich bezog mich mit "Hier" konkret auf das was ich zitiert habe.
Und PROGMEM ist eher eine Sache des Linkers, der Umgebung.
Der Compiler weiß davon eher nichts.

Matho schrieb:
> Irgendwas war da doch auch z.B. mit virtuellen
> Methoden!?
Ja?

Matho schrieb:
> Pseudocode
Ja, das habe ich jetzt verstanden.
Nein, leider weiß ich da auch keine Möglichkeit...
Weder mit constexpr noch mit Templates.

Außer:
Ein Miniprogramm schreiben, welches dir C/C++ Quellcode ausspuckt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Matho schrieb:
> Ich möchte gerne eine progmem-array erstellen, wobei:
>
1
> array[i] = fkt(i,Size); //Size:Template-Parameter, i:Index
2
>

Der schlüssel zum Erfolg liegt hier in `integer_sequence` und 
fold-expressions.

von Absolvent (Gast)


Lesenswert?

Das wurde doch im anderen Thread jetzt hinreichend besprochen. Dieser 
Thread hier kann dann doch abgeschlossen werden.

von Wilhelm M. (wimalopaan)


Lesenswert?

Wilhelm M. schrieb:
> Matho schrieb:
>> Ich möchte gerne eine progmem-array erstellen, wobei:
>>
1
>> array[i] = fkt(i,Size); //Size:Template-Parameter, i:Index
2
>>
>
> Der schlüssel zum Erfolg liegt hier in `integer_sequence` und
> fold-expressions.

Ich vergaß: und natürlich constexpr lambda-expressions als IIFE 
(immediately invoked function expressions);

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Der schlüssel zum Erfolg liegt hier in `integer_sequence` und
> fold-expressions.

Wilhelm M. schrieb:
> Ich vergaß: und natürlich constexpr lambda-expressions als IIFE
> (immediately invoked function expressions);

Arduino ist noch auf C++11

C++17 nur mit inoffiziellem Update des AVR Core und Toolchain
Und mit STL sowieso nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> Der schlüssel zum Erfolg liegt hier in `integer_sequence` und
>> fold-expressions.
>
> Wilhelm M. schrieb:
>> Ich vergaß: und natürlich constexpr lambda-expressions als IIFE
>> (immediately invoked function expressions);
>
> Arduino ist noch auf C++11

Wer spricht von Arduino?

> C++17 nur mit inoffiziellem Update des AVR Core und Toolchain

Der offizielle avr-gcc 8.2.0 (C++17) ist dafür ausreichend.

> Und mit STL sowieso nicht.

Wer spricht von STL?

von Einer K. (Gast)


Lesenswert?

Stimmt, d hast du Wahr.
Mein Fehler.

Und du weißt wie es geht und zeigst es nicht.
Sei stolz darauf und reibe es jedem unter die Nase.
.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Stimmt, d hast du Wahr.
> Mein Fehler.
>
> Und du weißt wie es geht und zeigst es nicht.
> Sei stolz darauf und reibe es jedem unter die Nase.

Hier die Umsetzung. Natürlich sollte man den Generator noch als 
template-template-Parameter parametrierbar machen, was ich hier aber 
unterlassen habe, denn die Kommentare der Unleserlichkeit kommen ja 
sicher schon bei diesem Beispiel:
1
#include <cstdint>
2
#include <cstddef> 
3
#include <cassert> 
4
#include <std/utility>
5
#include <avr/pgmspace.h>
6
7
template<auto Size>
8
struct PgmArray {
9
    template<typename> struct Generator;
10
    using mapper = Generator<std::make_index_sequence<Size>>;
11
    inline static char value(size_t index) {
12
        assert(index < Size);
13
        return pgm_read_byte(&mapper::data[index]);
14
    }
15
    template<auto... Index>
16
    struct Generator<std::index_sequence<Index...>> {
17
        inline static constexpr char data[Size] PROGMEM = {[](auto v){return v * 2;}(Index)... }; 
18
    };
19
};
20
21
using a1 = PgmArray<10> ;
22
23
int main() {
24
    return a1::value(2);
25
}

Die Realisierung von std::index_sequence und/oder 
std::make_index_sequence überlasse ich dem Leser. Oder man schaut halt 
mal in die C++-Standard-Bibliothek hinein ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

Kleiner Nachtrag: wer einen gcc > 9.0.0 zur Verfügung hat, kann auch 
lambda-expressions in sog. unevaluated-contexts sowie dann auch 
default-constructible closures verwenden:
1
#include <cstdint>
2
#include <cstddef> 
3
#include <cassert> 
4
#include <utility>
5
#include <avr/pgmspace.h>
6
7
using cppversion = std::integral_constant<long, __cplusplus>;
8
9
//cppversion::_;
10
11
struct Functor {
12
    constexpr char operator()(auto v) const {
13
        return 2 * v;
14
    }
15
};
16
17
auto l1 = [](auto v){return 2 * v;};
18
19
template<auto Size, typename F>
20
struct PgmArray {
21
    template<typename> struct Generator;
22
    using mapper = Generator<std::make_index_sequence<Size>>;
23
    inline static char value(size_t index) {
24
        assert(index < Size);
25
        return pgm_read_byte(&mapper::data[index]);
26
    }
27
    template<auto... Index>
28
    struct Generator<std::index_sequence<Index...>> {
29
        inline static constexpr char data[Size] PROGMEM = {
30
            F()(Index)... 
31
        }; 
32
    };
33
};
34
35
using a1 = PgmArray<10, Functor>;
36
using a2 = PgmArray<5, decltype(l1)>; // -> default constructible closures neccessary
37
//using a2 = PgmArray<5, decltype([](auto v){return 2 * v;})>; // -> lambda in ue-context
38
39
int main() {
40
    if constexpr(cppversion::value > 201703) {
41
        return a1::value(2) + a2::value(1);
42
    }
43
    else {
44
        return a1::value(2);
45
    }
46
}

von Einer K. (Gast)


Lesenswert?

Ich möchte dir für deine Mühe danken.
Danke!


Wilhelm M. schrieb:
> wer einen gcc > 9.0.0 zur Verfügung hat,
Leider kann ich das nicht (so einfach) testen.
Den Rahmen habe ich vorher schon genannt.
Genauer: avr-gcc 7.3.0 ist z.Zt. meine obere Grenze

Der Code ist aber zur weiteren Bearbeitung vorgemerkt.

Wilhelm M. schrieb:
> denn die Kommentare der Unleserlichkeit kommen ja
> sicher schon bei diesem Beispiel
Natürlich...
Ich empfinde das auch (noch?) als recht unleserlich, und wenig intuitiv 
erfassbar.

Ansonsten, lass sie schimpfen.
z.B. Ich akzeptiere gerne Lob/Kritik von Leuten, die es besser können.

Und ein "Besser" muss hier erst mal belegt werden.
Dann ist noch genug Zeit für Urteile und meckern.


Tipp:
Je mehr die Leute meckern, desto weniger investieren sie darin, das zu 
verstehen, worüber sie meckern.

Oder anders:
Die Intensität des Geschreis ist häufig proportional zu der Dicke des 
Brettes vor dem Schädel.

Wilhelm M. schrieb:
> Wer spricht von STL?
Naja, du selber setzt sie hier ein.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Wilhelm M. schrieb:
>> wer einen gcc > 9.0.0 zur Verfügung hat,
> Leider kann ich das nicht (so einfach) testen.
> Den Rahmen habe ich vorher schon genannt.
> Genauer: avr-gcc 7.3.0 ist z.Zt. meine obere Grenze

Das war aber beim TO nicht genannt (auch keine Beschränkung auf 
Arduino-IDE).

> Wilhelm M. schrieb:
>> Wer spricht von STL?
> Naja, du selber setzt sie hier ein.

Nein.
i)  die STL ist etwas anderes als die C++-Standardbibliothek.
ii) da es für AVR keine C++-Standardbibliothek gibt, habe ich mir meine 
eigene Version geschrieben mit bestimmten Besonderheiten (auch für AVR).

von Einer K. (Gast)


Lesenswert?

Ich sehe schon, dein Verständnis dafür, dass ich das leider nicht testen 
kann hält sich in Grenzen.
Is ok....

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino Fanboy D. schrieb:
> Ich sehe schon, dein Verständnis dafür, dass ich das leider nicht testen
> kann hält sich in Grenzen.

Wie gesagt: die aktuelle gcc Version ist 8.2.1. Damit kannst Du schon 
mal die Functor-Variante testen ;-)

: Bearbeitet durch User
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.