Hallo zusammen,
ich bin auf eine interessante clang++/g++-Erweiterung gestoßen, die auch
im avr-g++ enthalten ist und damit auch für bare-metal ganz iterressant
erscheint. Es geht um den user-defined-literal Operator für
string-literale als variadisches template. Damit lässt sich die
Umwandlung schon zur Compile-Zeit machen und so ein DT für Strings im
Flash darstellen. Im C++-14 Standard ist bislang nur der raw-operator
für Integrale/ Floats definiert.
Forgendes Beispiel mach das deutlich:
1
#include"console.h"
2
#include"simavr.h"
3
#include"pgmstring.h"
4
5
usingterminal=SimAVR;
6
7
namespacestd{
8
std::basic_ostream<terminal>cout;
9
std::lineTerminator<CRLF>endl;
10
}
11
12
intmain()
13
{
14
autofs1="xyz"_pgm;
15
std::cout<<fs1<<std::endl;
16
std::cout<<"abce"_pgm<<std::endl;
17
}
Alle Strings mit dem Suffix _pgm werden zu Klassen mit einem statischen
Datenelement, dass dann im flash liegt. Durch entsprechende
Funktionsüberladung (hier der op<<) kann man sie auch gleich ausgeben.
Das witzige dabei ist, dass ja ein Template zusammen mit seiner
Parametrierung ein DT ist. Also: unterschiedliche Stringliterale ergeben
unterschiedliche statics im flash, gleich Stringliterale ergeben
dasselbe(!)
static im flash.
Die Implementierung sieht so aus:
Könnte im Prinzip funktionieren. Allerdings scheint mir die str()
Funktion unbrauchbar: Der Pointer, der zurückgegeben wird, zeigt ins
Flash, aber wird vom Aufrufer wie ein normaler RAM-Pointer behandelt.
Das wird nicht gut gehen. Es wird wohl notwendig sein, operator<<() und
alle weiteren Nutzungsszenarien als Member-Funktionen zu implementieren,
damit der String mittels pgm_read_byte() ausgelesen wird.
Aber bisher nur mit "simavr.h", richtig? Ich bin mal gespannt, ob der
GCC bereit ist data[] in den Flash zu legen.
Ich hab da auch schon mit gespielt und geben Zeiten/Frequenzen nun so
an:
10_mSec, 1.5_Sec, 17_kHz, ...
Am Ende steht immer ein "constexpr unsigned long" mit den notwendigen
Takten abgeleitet aus F_CPU. Da muß man sich das Umrechnen nur einmal
ausdenken und schreit dann zukünftig was man eigentlich meinte.
Geht aber halt nur, wenn man auf C noch eins draufsattelt ;-)
Geht auch im echten Leben ;-)
Die literal-operatoren sollten eigene DT (etwa Hertz oder MegaHertz oder
Milliseconds ...) zurückgeben. Dann kann man sich die anderen Operatoren
auch schreiben und so ein ganzen physikalisches System bauen.
Also: 1_MHz / 1KHz -> 1000
Aber das ist mittlerweile ja normal in C++ ...
Nur der Vollständigkeit halber:
> Im C++-14 Standard ist bislang nur der raw-operator für Integrale/ Floats> definiert.
"User Defined String Literals" sind ein C++14 Feature und keine GCC
Erweiterung.
Aber dein Code hat mich dazu gebracht mir das nochmal im Detail bei
cppreference.com anzuschauen. Das ich das auch variadic-template'n kann,
hatte ich noch gar nicht entdeckt. Reduziert doppelten Code, denn
Integer- oder Float-Versionen meiner Zeiten/Frequenzen unterscheiden
sich nur in den Parametern. Quasi negativer Source-Code-Bloat ;-)
Carl D. schrieb:> Nur der Vollständigkeit halber:>> Im C++-14 Standard ist bislang nur der raw-operator für Integrale/ Floats>> definiert.>> "User Defined String Literals" sind ein C++14 Feature und keine GCC> Erweiterung.
Bitte genau lesen: der "template literal operator" (!!!) für
string-literale, also "text"_bla ist eine gcc/clang Erweiterung!
Der "template literal operator" für ganzzahlige / fließkomma-Literale
ist ab C++11 da (etwa 100_km)
Das ist ein Unterschied!
s.a: http://en.cppreference.com/w/cpp/language/user_literal
Wilhelm M. schrieb:> Der Typ ist dann PgmString wie Du siehst, und dafür ist op<< überladen.
Den Typ sehe ich, aber dass operator<< überladen wäre, geht aus deinem
Code nicht hervor.
Ah, jetzt sehe ich, dass du da etwas mit basic_ostream<terminal>
zauberst. Damit habe ich keine Erfahrung. Ich muss glauben, was du
sagst...
Insgesamt ist dein Vorgehen natürlich eine gute Idee.
tictactoe schrieb:> Wilhelm M. schrieb:>> Der Typ ist dann PgmString wie Du siehst, und dafür ist op<< überladen.>> Den Typ sehe ich, aber dass operator<< überladen wäre, geht aus deinem> Code nicht hervor.>> Ah, jetzt sehe ich, dass du da etwas mit basic_ostream<terminal>> zauberst. Damit habe ich keine Erfahrung.
Hier ist
1
terminal
einfach eine Wrapper-Klasse um den Debug-Port des simavr. Generell kann
man aber einfach irgendeinen USART zum Terminal erklären:
Nochmal auf dein FlashString-Beispiel zurückzukommend:
- was ist die gcc-Erweiterung und wie schaltet man sie ein?
Mein gcc 6.2 -std=c++14 legt zwar den String brav in den Flash, gleich
nach den Int-Vektoren, aber kann darauf nicht zugreifen.
- was steht in deiner "console.h" und in "simavr.h"?
- woher kommt std::basic_ostream ?
Welche clang Version hat ein AVR Backend?
Bitte überzeug mich, daß du recht hast.
Carl D. schrieb:> Nochmal auf dein FlashString-Beispiel zurückzukommend:> - was ist die gcc-Erweiterung und wie schaltet man sie ein?
gar nicht.
Wenn Du sie benutzt und -Wgnu-string-literal-operator-template
verwendest bekommst Du auch die passende Warung.
> Mein gcc 6.2 -std=c++14 legt zwar den String brav in den Flash, gleich> nach den Int-Vektoren, aber kann darauf nicht zugreifen.
Warum nicht?
Falls es um den op<< geht, muss Du dann natürlich pgm_read_byte()
verwenden.
> - was steht in deiner "console.h" und in "simavr.h"?
die überladenen op<<
> - woher kommt std::basic_ostream ?
von mir ;-)
> Welche clang Version hat ein AVR Backend?
keine, das bezog sich ja nur auf die extension, die beide unterstützen.
Wilhelm M. schrieb:> Carl D. schrieb:>> Nochmal auf dein FlashString-Beispiel zurückzukommend:>> - was ist die gcc-Erweiterung und wie schaltet man sie ein?>> gar nicht.> Wenn Du sie benutzt und -Wgnu-string-literal-operator-template> verwendest bekommst Du auch die passende Warung.
Sorry, das ist eine Option von clang++ und nicht vom g++, also auch
nicht vom avr-g++
autofs1="xyz"_pgm;// hinterläst brav string im Flash
3
v8=pgm_read_byte(fs1.str());// liest brav ein byte aus Flash
4
5
std::cout<<"ABC"_pgm;// gibt ABC über "copy&paste" ostrem aus
6
// Danke an Konstantin Chizhov
7
std::cout<<fsl;// ???
8
...
ergibt: error: 'fsl' was not declared in this scope
Angesichts der Tatsache, daß jeder PgmString einen eigenen Typ bekommt,
funktioniert auch das:
1
intmain(){
2
usingfs1="xyz"_pgm;// hinterläst brav string im Flash
3
v8=pgm_read_byte(fs1::str());// liest brav ein byte aus Flash
4
5
std::cout<<"ABC"_pgm;// gibt ABC über "copy&paste" ostrem aus
6
// Danke an Konstantin Chizhov
7
std::cout<<fsl;// ???
8
...
liefert aber exakt die gleiche Fehlermeldung.
In welchem Scope könne der Compiler das Symbol fsl, ob Variable oder
Typ, egal, denn versteckt haben?
Nebenbei: der SyntaxHighlighter kann kein C++ >= 11 (using)
Guest schrieb:> fsl!=fs1
Schande über mich!!!
einmal (mit alten Augen) nicht kopiert, sondern selbst (ab-)geschrieben.
Jetzt versteh ich auch den komischen Namen.
Nicht "fussel", sondern "FlashString1".
Ich brauch eine bessere Brille, besseres Display, bessere Fonts ...
Danke für den anonymen Tip!
Oder einfach mal in der Zeile den Fehler suchen, die vom Compiler
angezeigt wird ;-) Oder einen besseren Editor verwenden (vim, emacs)
oder IDE (qtcreator) ...
Wilhelm M. schrieb:> Was ist denn "copy&paste" ostream?
naja, eine Handvoll Includes, die ich mir bei Mcucpp geborgt hab.
ostream<terminal> (mit terminal::put auf PortB, damit das ganze nicht
wegoptimiert wird) lief so innerhalb 5 Minuten und ein operator<< für
FlashString war in der Zeit schon mit drin.
Nur die 1 von einem l zu unterscheiden hab ich ohne fremde Hilfe nicht
hinbekommen. ;-)
(wobei, bei meinem alten iPad in Normalgröße unterscheiden die sich auch
nur um ein Pixel, wie ich gerade nach Vergrößern sehe)
Na wunderbar!!!
Wie gesagt (in einem anderen Thread), bin ich dabei, meine gesamte
uC-Code-Basis auf C++14/17/20 umzustellen und komme aus der Begeisterung
gar nicht mehr heraus ;-)
Wilhelm M. schrieb:> Na wunderbar!!!>> Wie gesagt (in einem anderen Thread), bin ich dabei, meine gesamte> uC-Code-Basis auf C++14/17/20 umzustellen und komme aus der Begeisterung> gar nicht mehr heraus ;-)
Das Gefühl herrscht bei mir auch gerade (mal wieder).
Hatte ich vor C++11 schon mal versucht und mich in <loki> verfangen.
Das Klassentemplate PgmString<> ist dazu da, zu Compile-Zeit ein
C-String mit dem suffix _pgm, etwa "abc"_pgm im Flash abzulegen und dies
dann so zu kapseln, dass man sich nicht mehr um das lesen aus dem Flash
mit pgm_read_byte(), etc. kümmern muss.
Zusätzlich: wenn im Programm mehrfach bspw. "abc"_pgm vorkommt, so wird
im Flash das nur einmal abgelegt, ohne dass ich mich als Programmierer
drum kümmern muss.
Nico W. schrieb:> Warum eigentlich so kompliziert und nicht einfach__flash nutzen?
Weil das eine nur für C verfügbare Erweiterung ist, die auf "named
memspaces" auf der EmbededC Definition aufsetzt. Für C++ gibt's das
leider nicht. Harward-Architektur ist leider (noch(Hoffnung)) nicht die
Zielgruppe des ISO-CPP-Gremiums. Und GCC hat versprochen, sich an den
Standard zu halten.
Man könnte sonst z.B. nicht nur den __flash MemorySpace, sondern auch
einen __eeprom MemorySpace im AVR-GCC bauen und dann statt LDM
entsprechende Calls in die EEProm-Leseroutinen machen.
Wilhelm M. schrieb:> __flash ist ein non-standard keyword von IAR.
nicht mehr:
6.16 Named Address Spaces
As an extension, GNU C supports named address spaces as defined in the
N1275 draft of ISO/IEC DTR 18037. Support for named address spaces in
GCC will evolve as the draft technical report changes. Calling
conventions for any target might also change. At present, only the AVR,
SPU, M32C, RL78, and x86 targets support address spaces other than the
generic address space.
Address space identifiers may be used exactly like any other C type
qualifier (e.g., const or volatile). See the N1275 document for more
details.
Oh, dass das der gcc macht als Erweiterung, ist mir entgangen ...
Naja, der g++ macht's halt nicht. Auf der anderen Seite hat man sich das
ja nun auch schnell gekapselt. Selbst wenn man das literal operator
template for string-literals nicht verwenden würde.
Wilhelm M. schrieb:> Zusätzlich: wenn im Programm mehrfach bspw. "abc"_pgm vorkommt, so wird> im Flash das nur einmal abgelegt, ohne dass ich mich als Programmierer> drum kümmern muss.
thumbs up!
Wie würde man denn auf solche Strings zugreifen? Etwa so?
1
template<typenameC,C...CC>
2
structPgmString
3
{
4
...
5
6
charoperator[](size_tpos)const
7
{
8
if(__builtin_constant_p(pos))
9
returnchar_at(pos);
10
else
11
returnpgm_read_byte(data+pos);
12
}
13
14
private:
15
staticconstexprcharchar_at(size_tpos)
16
{
17
returndata[pos];
18
}
19
};
Das eigentliche Problem scheint aber zu sein, mit solchen Strings zu
hantieren und sie zu übergeben:
1
???get_ok_str(boolok)
2
{
3
returnok?"good"_pgm:"bad"_pgm;
4
}
Das kann natürlich nicht funktionieren, weil die Strings
untersciedlichen Typ haben. Und sobald man die .str() Methode verwendet
hat man eh verloren: Dann muss pgm_read wieder händisch gemacht werden,
und das ganze Template-Geraffel ist nur eine extrem unübersichtliche
Variante einen Stringf ins Flash zu bekommen.
Wie wüde denn ein Beispiel mit Wochentagen aussehen, d.h. ein Lookup von
strings, das einen Index auf einen Wochentag-String abbildet?
Oder allgemeiner eine LUT mit Integern?
Da stellt sich die Frage: was möchtest Du dann machen? Sollen die
Strings im Flash als immutable bleiben oder möchtest Du sie im RAM
haben.
Sollen Sie im Flash bleiben bittet sich ein Thin-Wrapper an:
Wilhelm M. schrieb:> Da stellt sich die Frage: was möchtest Du dann machen?
Ich würde gern ein besseres Verständnis dieser C++ Abartigkeiten[tm]
bekommen und ob sich die Terz irgendwie lohnt. Wenn ich gefühlt 30
Zeilen Code brauche, um einen 1-Zeiler in C wie
1
const__flashdata_tdata[]={...};
abzubilden, dann sinkt die Attraktivität schon spürbar. Um so mehr, als
ich selbst nicht auf all diese Konstrukte gekommen wäre.
> Sollen die> Strings im Flash als immutable bleiben oder möchtest Du sie im RAM> haben.
Weder noch, mich interessiert, wie ein allgemeiner Ersatz von __flash
sinnvoll aussehen würde. Bei __flash ist die Verwendung egal; ich
verwende das Zeug eben wie normale Daten mit normalem C-Code. Was
angepasst werden muss sind Zeiger, die entsprechend qualifiziert werden
müssen.
Und ein Großteil der Daten sind oft eben keine Strings, sondern andere
Daten wie Strukturen oder Arrays davon.
> Sollen Sie im Flash bleiben bittet sich ein Thin-Wrapper an:>> [c]> class PgmStringView {> public:> const char* p = nullptr;> };
Wozu brauche ich denn diesen schon wieder? Der macht doch das gleiche
wie .str().
> class MessageCatalog {> public:> enum Id {first= 0, second, NumberOfMessages};> static PgmStringView message(enum Id index) {> return messages[index];> }>> private:> static const PgmStringView messages[];> };>> const PgmStringView MessageCatalog::messages[NumberOfMessages] = {> "abc"_pgm,> "def"_pgm,> };
D.h. es ist nicht möglich, Arrays von PgmStringView anzulegen, und
desshalb muss stattdessen eine neue Klasse MessageCatalog implementiert
werden?
Aber das einzige was ich jetzt mit den Strings jetzt tun kann, ist doch
einen "const char*" zu bekommen, und dann mit pgm_read zuzugreifen?
Wenn ich sowas verwende, dann wäre ein Schema sinnvoll, das unabhängig
von der Verwendung ist. Ansonsten ist man ja ständig dabei, die
Applikation und alles umzustricken, nur weil sich an einer Stelle die
Verwendung ändert.
Johann L. schrieb:> Wilhelm M. schrieb:>> Da stellt sich die Frage: was möchtest Du dann machen?>> Ich würde gern ein besseres Verständnis dieser C++ Abartigkeiten[tm]> bekommen und ob sich die Terz irgendwie lohnt. Wenn ich gefühlt 30> Zeilen Code brauche, um einen 1-Zeiler in C wie>
1
const__flashdata_tdata[]={...};
> abzubilden, dann sinkt die Attraktivität schon spürbar. Um so mehr, als> ich selbst nicht auf all diese Konstrukte gekommen wäre.
Nun ja, das wär in C++ auch wirklich schön. Aber das C++-Committee wie
auch das C-Committee haben den Draft-xxxx (Nummer weiß ich grad nicht)
nicht akzeptiert. Allerdings ist der Draft im gcc und leider nicht im
g++ drin.
> Wozu brauche ich denn diesen schon wieder? Der macht doch das gleiche> wie .str().
Dem const char* sehe ich aber nicht an, dass er anders behandelt werden
muss / sollte. Primitive DT wie int, double, etc. und char* tragen eben
keine Semantik. Dafür sind dann solche "domänen-spezifischen" DT da. Ein
PgmStringView muss ich ja mit pgm_read_... bearbeiten.
> D.h. es ist nicht möglich, Arrays von PgmStringView anzulegen, und> desshalb muss stattdessen eine neue Klasse MessageCatalog implementiert> werden?
Doch. Steht ja da.
> Aber das einzige was ich jetzt mit den Strings jetzt tun kann, ist doch> einen "const char*" zu bekommen, und dann mit pgm_read zuzugreifen?
s.o.
Man braucht sich dann aber bei der Verwendung nicht mehr drum zu
kümmern, ob es nun Daten aus dem RAM oder Flash sind. Also so ähnlich
wie bei __flash.
Summa summarum:
1) das Attribute __flash wäre schön im g++, ist aber nicht drin, und
wird auch nicht reinkommen, sofern der Draft ein Draft bleibt
2) Einen (internationalisierten) Nachrichtenkatalog aus PgmString zu
bauen ist eigentlich nicht sinnvoll. Das macht man besser mit nackten
C-Strings im progmen, die dann von der Klasse MessageCatalog o.ä. in ein
PgmStringView (ist ja auch nur ein Zeiger) gewandelt wird. Denn die
Strings im katalog werden wohl alle unterschiedlich sein.
3) Wahrscheinlich ist eine Mischlösung: MessageCatalog in C-Quelldatei
mit __flash und ThinWrapper in C++ sinnvoll(er).
Johann L. schrieb:> Wenn ich gefühlt 30> Zeilen Code brauche, um einen 1-Zeiler in C wie
Das ist die Faszination von Templates. Ganz gegen den immer noch
allgemeingültigen Spruch "premature optimization is the root of all
evil" verführen die genau dazu.
Ich hab den Versuch auch schon hinter mit, ob es nicht gelingt, das der
Compiler an die 1000 Zeilen C++-Templatecode in nur eine einzige
Assembleranweisung übersetzt. Und ja, das geht ;)
Der praktische Sinn bleibt bei solchen Fingerübungen schnell auf der
Strecke. Aber lustig ists schon.
Oliver
Oliver S. schrieb:> Ich hab den Versuch auch schon hinter mit, ob es nicht gelingt, das der> Compiler an die 1000 Zeilen C++-Templatecode in nur eine einzige> Assembleranweisung übersetzt. Und ja, das geht ;)>> Der praktische Sinn bleibt bei solchen Fingerübungen schnell auf der> Strecke. Aber lustig ists schon.
Ich würde sogar soweit gehen und behaupten, so etwas trägt dazu bei,
dass der Code noch viel unleserlicher wird als ohne diese Templates.
Gerade bei excessiver Verwendung von überladenen Operatoren verliert man
schnell den Überblick. Ich nutze auch C++, aber nicht um jeden Preis.
Wenn ein anderer stundenlang braucht um meine geistigen Ergüsse zu
verstehen habe ich was falsch gemacht. Jeder der AVRs programmiert hat
sich mit der Besonderheit der Strings im Flash abgefunden und kann damit
umgehen. Warum muss man da wieder ein neues Rad erfinden?
Johann L. schrieb:> Wenn ich gefühlt 30> Zeilen Code brauche, um einen 1-Zeiler in C wie
Das ist (näherungsweise) so, als würde man deine 4-stellige Anzahl
Zeilen im AVR-Backend gegen die C eingesparten Zeilen Assembler-Code
verrechnen wollen. Man versucht (manchmal erfolgreich) in einen Header
Berge von Templates und ConstExpr's zu stecken, die in der eigentlichen
Source gut lesbaren Code hinterlassen. Das Haeder-File muß man, wenn es
mal funktioniert nicht mehr anschauen, wenn das zu stark erschreckt.
Zu der Frage "wie komm ich an die FlashStrings": Man würde bei so was
versuchen den "="-Operator zu überladen, nur geht das hier nicht, denn
dieser muß eine Member-Funktion sein, d.h. Ziel ist das aktuelle Objekt
"*this". Variabel kann der Quellwert sein. Da aber ein solcher "Wert"
wie hier, ein Typ mit einen Statischen Datenbereich (der bei AVR auch
das Attribute "Flash" haben kann) ist, gibt es kein Objekt und selbst
wenn, es soll ja Quelle und nicht Ziel sein.
Andere Operatoren können mit 2 Parametern definiert werden, z.B.:
(Das ist nur das Konzept und hat Auskassungen (die beiden "~") sowie
wurde auf dem Pad getippt, hat also sicher Syntax-Probleme)
Das geht für die Strings des TO mit einer operator<< Variante, die in
eine Stream schreibt, ich hab das gestern Abend auch noch (mit jeweils
10 Zeilen Code) für POD, sowie POD[] hinbekommen. Wenn ich wieder am
Rechner bin mehr.
Bei Strukturen häng ich an dem Problem nicht-Typ-Gleiche
Initialisierung-Parameter zur Compile-Time in eine statisches Variable
zu packen. Mit n-mal der gleiche Typ geht das leicht.
Seit gestern ist mir auch klar, warum man die shift-Operatoren so gerne
überläd. ;-)
Ps: das coole ist, ich kann diese Konstante n-mal neu definieren, also
an 100 Stellen das Literal "OK"_pgm ausgeben. Es bleibt ein (vom Inhalt
abhängiger) Typ mit einer einzigen statischen Konstante im Flash.
Carl D. schrieb:> Johann L. schrieb:>> Wenn ich gefühlt 30>> Zeilen Code brauche, um einen 1-Zeiler in C wie>> Ps: das coole ist, ich kann diese Konstante n-mal neu definieren, also> an 100 Stellen das Literal "OK"_pgm ausgeben. Es bleibt ein (vom Inhalt> abhängiger) Typ mit einer einzigen statischen Konstante im Flash.
Genau darum ging es mir ja!!! Nichts anderes zunächst einmal. Weil ich
auch oft - sinnvoll oder nicht - an vielen Stellen im Code
String-Literale hingeschrieben habe.
Und ich würde es nicht für einen Message-Catalog einsetzen. Das mache
ich ähnlich wie bei "normalen, hosted" C++-Applikationen: man hat
message-identifier die je nach locale auf die richtige
Meldung/Formatierung/Währungssymbol/you-name-it abgebildet werden.
Aber vor allem geht es darum: ein Interface soll leicht richtig und nur
sehr schwer falsch zu benutzen sein. Es soll nicht möglich sein, einen
C-String, der im flash ist, wie einen C-String im RAM zu behandeln. Das
geht nämlich bei g++ (s.o.) wegen des fehlenden __flash Attributes
schief ...
Wilhelm M. schrieb:> Aber vor allem geht es darum: ein Interface soll leicht richtig und nur> sehr schwer falsch zu benutzen sein. Es soll nicht möglich sein, einen> C-String, der im flash ist, wie einen C-String im RAM zu behandeln.
Ich hab nun 2 Abende damit rumgespielt und muß das vielleicht mal in
einen Artikel packen. Kurz (und wieder auf dem Pad und deshalb nur als
Gedächtnisprotokol):
1
// Strings; Dir bekannt ;-) sind eigentlich Character Arrays
2
charca[10];
3
ca<<"Flash"_pgm;// Lesen, Länge ergibt sich aus Quelle UND Ziel
Viele Detailfragen sind noch offen, aber es geht prinzipiell.
> Das geht nämlich bei g++ (s.o.) wegen des fehlenden __flash Attributes> schief ...
__flash ist aber kein Attribute, sondern ein Type-Qualifier, so wie
const und volatile. Das ist somit Teil des Sprachstandards und über den
wacht das Kommitee.
Ja, mit EEProm geht das natürlich auch.
> __flash ist aber kein Attribute, sondern ein Type-Qualifier, so wie> const und volatile. Das ist somit Teil des Sprachstandards und über den> wacht das Kommitee.
Ja, Du hast natürlich recht: ist ein type qualifier. Allerdings wie
gesagt ist N1275 ein Draft (!) für C und deswegen nicht in C11 drin, und
nicht für C++, deswegen nicht in C++11 ff. drin. AFAIK auch nicht für
C++17/20 scheduled :-(
@Carl Drexler
Bitte die Programm-Schnipsel dieses Threads zu einem compilierbaren
Beispiel zusammenfassen und den verwendeten Compiler benennen.
Dann könnte ich eventuell frei nach Sesamstrasse die Fragen nach "wer",
"wie", "was", "wieso", "weshalb", "warum" auch selber beantworten.
Meine aktuellen Randbedingungen:
*******************************
Mcucpp,
Atmel-Studio6.2 und
avr-gcc-8.0_2017-07-19_mingw32