Wenn sizeof(any struct/data type) gebraucht wird und nicht per Hand
berechnet werden soll, dann kann gcc via warning info das erledigen.
Die Notwendigkeit die Speichergröße von komplexenn Strukturen zu kennen
war Impuls in stackoverflow, ... zu suchen.
1
//get warning at compile time about sizeof(any data tpye)
Apollo M. schrieb:> Die Notwendigkeit die Speichergröße von komplexenn Strukturen zu kennen> war Impuls in stackoverflow, ... zu suchen.
Meist brauche ich die nur im Code. Und wenn nicht, schreib ich mir ein
kleines Programm, das sie mir per printf ausgibt. Warum sollte ich dazu
Warnungen missbrauchen?
Bauform B. schrieb:> _Static_assert
Auch Compile-tume-assert genannt. Gibt es auch in C selbstgemacht, auch
in alten Varianten.
Static-asserts sollte jeder kennen und bei Bedarf nutzen.
Apollo M. schrieb:> Wenn sizeof(any struct/data type) gebraucht wird und nicht per Hand> berechnet werden soll,
Dann hat man die Kontrolle über sein Leben verloren.
Wenn du exakte Kontrolle über eine Datenstruktur haben musst, dann baue
sie byteweise (notfalls sogar bitweise) zusammen. Das nennt sich
marshalling. Proaktiv statt reaktiv.
Ansonsten steht man früher oder später mit runtergelassener Hose da,
weil man solche Dinge wie "wie groß ist der Datensatz wirklich und wie
ist das Encoding" nur mit "was der Compiler halt eben gerade heute, bei
aktueller Mondphase draus macht" beantworten kann.
Die Discussion zu dem Thema in stackoverflow ist umfangreich, also gibt
es - wie für mich auch - im Ausnahmefall wohl Sinn/Nutzen.
Der Hintergrund zu dem Thema ...
Eine struct soll ans Ende im eeprom plaziert werden - was vermutlich
eleganter mit linked extra Segment geht ... Aber wie genau (avr-gcc,
as7)?
Dazu definiere ich die struct in der size des eeprom und plaziere ein
unused array mit size E2END (end addr eeprom) minus size der struct ee
Elemente, die ich aber nicht via sizeof bestimmen kann.
Ohne unused array wird mit mSizeOfWarning(ee) die size of struct ee zur
Compilierzeit angezeigt und kann dann für die unused array size XXX
genutzt werden.
Apollo M. schrieb:> EEMEM struct ee_t {> uint8_t> unused[E2END+1-(XXX+sizeof(SWID)-1)]> oscCal[12],> TimerOperation,
Es wurde oben schon geschrieben, dass man bei sowas auf das alignment
bzw. padding achten muss um nicht mit einem anderen Compiler oder auch
nur geänderten Compiler Optionen Überraschungen zu erleben. Nicht nur
die Größe ist wichtig, jeder einzelne Offset ist entscheidend.
Grundsätzlich bedeutet dies für solche Strukturen das alignment fest zu
definieren, siehe z.B. hier:
https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
Noch besser ist es, wenn man die Struktur selbst so definiert, dass das
alignment des Compilers egal ist, d.h. man sortiert die Reihenfolge
der Member entsprechend und fügt ggf. händisch padding bytes ein.
Michael
Apollo M. schrieb:> Dazu definiere ich die struct in der size des eeprom und plaziere ein> unused array mit size E2END (end addr eeprom) minus size der struct ee> Elemente, die ich aber nicht via sizeof bestimmen kann.> Ohne unused array wird mit mSizeOfWarning(ee) die size of struct ee zur> Compilierzeit angezeigt und kann dann für die unused array size XXX> genutzt werden.
Das dir die Größe bei der Warnung angezeigt wird, ist toll. Wenn ich
sowas gebraucht habe, habe ich manchmal mehrmals compiliert mit
static-asserts oder hab das Programm extra dafür laufen gelassen (mit
Ausgabe des Wertes, wo auch immer, Debugger, LED, printf, Display, ...).
Oder hab im Output nachgesehen. Alles recht aufwendig und hat teils
Minuten gedauert.
Vermutlich erinnere ich mich beim nächsten Mal an diese Möglichkeit und
freue mich, dass Du es damit einfach hast :-)
A. S. schrieb:> Alles recht aufwendig und hat teils Minuten gedauert.
So ist es, das war auch immer mein Problem.
Es werden verschiedene Methoden hins. entspr. Warning Info im Netz
diskutiert, die nicht bei jedem Compiler gleich gut funktionieren -
Warning kommt fast immer, aber ohen die Angabe des gesuchten Wertes. Bei
dem Macro hier spiel die -4242 eine unklare Rolle, +-1, +-100, ... geht
alles nicht - warum auch immer - aber >256 bringt das Warning mit Angabe
der gesuchten Zahl.
Ob/wie das mit einer extra section zum linken gehen könnte ist mir
unklar, da die Linker section start address über E2END+2-sizeof(ee_t)
berechnet werden muss.
Apollo M. schrieb:> Ob/wie das mit einer extra section zum linken gehen könnte ist mir> unklar, da die Linker section start address über E2END+2-sizeof(ee_t)> berechnet werden muss.
Warum? Die Größe der struct hast du doch selbst festgelegt:
Apollo M. schrieb:> Dazu definiere ich die struct in der size des eeprom
Wenn du für diese struct eine eigene section ganz normal (also auf eine
feste Startadresse) im Linkerscript anlegst, ist doch die Endadresse
automatisch durch die Größe gegeben. Ganz ohne weitere Berechnungen.
Bauform B. schrieb:> Wenn du für diese struct eine eigene section ganz normal (also auf eine> feste Startadresse) im Linkerscript anlegst, ist doch die Endadresse> automatisch durch die Größe gegeben. Ganz ohne weitere Berechnungen.
Die struct in der size des eeprom ist nur eine Hilfslösung, weil nicht
klar ist wie es sonst gehen könnte.
Entgegen der Festlegung über die Startadresse soll über die Endadresse
und size of data object die Plazierung im eeprom erfolgen.
Wahrscheinlich unrealistisch ...
Na gut, du hast es so gewollt ;) ee_t enthält jetzt nur noch Nutzdaten,
kein unused[] mehr. Die letzte Adresse im EEPROM ist bekannt. Man
definiert eine section mit dieser Adresse+1 als Start. Die struct ee_t
ee wird in die neue section gelinkt, also hinter das EEPROM. Dann
nimmt man einen Pointer auf diese struct und dekrementiert den einmal.
Damit zeigt er auf eine ee_t struct im EEPROM und die endet genau auf
der letzten Adresse.
So muss niemand jemals die Größe von irgendwas erfahren, alles passt
ganz von alleine zusammen. Trotzdem würde ich die section genau so groß
machen wie das EEPROM. Einmal zwecks der Schönheit und dann zwecks der
Warnung, falls ee_t irgendwann zu groß wird.
Mit dem Alignment muss man trotzdem aufpassen, falls mal größere
Datentypen als uint8_t gebraucht werden. Es wird zwar immer
funktionieren, weil die section ja auf deutlich mehr als 4 aligned ist.
Aber evt. bleiben am Ende 1 bis ein paar Byte "Luft".
Bauform B. schrieb:> Na gut, du hast es so gewollt ;)
Das muss ich erstmal durchdenken und ausprobieren - blicke es noch nicht
wirklich.
Bauform B. schrieb:> Einmal zwecks der Schönheit und dann zwecks der Warnung,
Ja, schön ist die Lösung mit unused[] nicht und zwickt, also nicht im
Sinne "pythonic coding style". :-)
Ich bin Python Anhänger und habe am Anfang mit Python eher C coding
style programmiert mit Python Syntax - full ugly.
Gibt es außer Visual Studio eigentlich keine weitere IDE, die mir beim
Hovern über ein 'sizeof' die Größe im Editor anzeigt? Bei Eclipse & Co.
tut sich da leider nichts. :(
Bei solchen Dingen wär' ich vorsichtig.
Ich weiß nicht, wie IntelliSense das macht, aber zumindest die
OSS-Implementierungen verwenden (meist?) einen Language-Server im
Hintergrund und das LSP-Protokoll, um von dort Namen- und
Typinformationen zu bekommen.
Soweit ich das kenne, sind diese Language-Server (zumindest für C/C++)
meist clang-basiert.
Wenn man nun (z.B.) mit gcc compiliert (möglicherweise mit
Compiler-Optionen die die clang-Lib im LS gar nicht zu sehen bekommt,
weil sie im Makefile versteckt sind) wird da zwar was angezeigt, das
muss aber nicht unbedingt stimmen.