Eine C-Firmware, die ich mit dem Unit-Testframework "Google Test" testen
muss, wird mit der Compileroption "-fshort-enums" übersetzt. Enums
werden auch in Strukturen benutzt. Es ist wichtig, dass die Strukturen
die selbe Größe wie in der originalen Firmware besitzen. Die Firmware
wird mit dem AVR-GCC und das Testprogramm mit dem MINGW compiliert. Das
Testprogramm soll auf dem PC laufen.
Benutze ich "-fshort-enums" um das Testprogramm zu übersetzen, stürzt
das Programm mit einem Segmentation Fault ab. Das passiert beim
Verlassen eines Testfalls, der eine C-Funktion testet, in der ein Enum
benutzt wird. Entferne ich die Compileroption, tritt der "Segmentation
Fault" nicht mehr auf. Allerdings schlagen dann die Testfälle fehl.
Die Option nur für das C-File zu benutzten ist leider nicht möglich.
Denn es gibt globale Variablen und Funktionsparameter (zu testende
Funktionen und Mocks) die entsprechende Strukturen benutzen, und diese
müssen aus dem C++ Testprogramm heraus ebenfalls benutzt werden.
Meine Suche im Internet nach diesem Problem hat leider kein Ergebnis
zutage gefördert. Hat jemand eine Idee, wie man diesen Widerspruch lösen
kann? Gibt es relevante Optionen mit dem man das Google Test steuern
kann? Oder muss man das Google Test selbst mit dieser Option übersetzen?
Hast Du alle Bestandteile von "Google Test" ebenfalls mit -fshort-enums
kompiliert?
Vielleicht hilft es auch einfach nur das besagte Enum mit dem Attribute
_packed_ zu belegen und die Compileroptionen diesbezüglich komplett in
Ruhe zu lassen, das hat den gewünschten Effekt für die Größe genau
dieses enums und beeinflußt keinerlei anderen Sachen:
Vielen Dank für Eure Antworten.
Bernds Antwort war die Lösung:
#define PACKED _attribute_ ((_packed_))
typedef enum PACKED { // sizeof == 1
OT_NO_NC,
OT_NC_NO,
OT_NO,
OT_NC
} settings_outtype_t;
Mir war nicht bewusst, daß man das Attribut _packed_ auch bei Enums
benutzen kann.
@Cer
Entsprechend Bernds Vorschlag, wird dieses Attribut auch für die
Strukturen angewendet. Ansonsten werden außerdem die folgenden Optionen
benutzt:
-mno-ms-bitfields -Wno-packed-bitfield-compat
Bitschubser schrieb:> Entsprechend Bernds Vorschlag, wird dieses Attribut auch für die> Strukturen angewendet.
Das würd ich nicht machen, stattdessen würde ich (wenn es nicht schon zu
spät ist) die Elemente so anordnen daß gemäß self-alignment Regeln gar
kein Padding entstehen kann! (Vgl. ESR: "Lost Art of Structure
Packing") Somit hast Du sowohl platzmäßig das selbe Ergebnis wie packed
und zusätzlich noch die Gewissheit daß der Compiler dennoch keine
Verrenkungen im Code erzeugen muß um auf krumm verschobene Datenworte
zuzugreifen weil alles trotz dichtestmöglicher Packung immer noch sauber
aligned ist.
@Bernd
Das ist mir schon klar, daß das die ideale Lösung wäre. Leider ist das
eine große Firmware und ich bin lediglich der Tester. Mal sehen ob sich
die Programmierer überzeugen lassen. :-)
@Oliver
Es werden die Datentypen aus der std_int.h benutzt. Also z.B.: int32_t
Nochmals vielen Dank!
Oliver S. schrieb:> Das int beim avr-gcc 16 Bit, im PC-Tetsprogramm aber 32 Bit hat, spielt> keine Rolle bei den Tests?
Wenn er vorausschauend ist (was ich vermute wenn er sich schon Gedanken
über Enum-Größen macht und diese erzwingen will) benutzt er keine
solchen Gummidatentypen wie int in binären Interfaces zur Außenwelt
sondern nagelt dort alles aufs Bit genau fest und dokumentiert das.
Nur mal so aus Interesse.
Ein bisschen verwirrt mich diese Lösung. Allerdings habe ich noch nie
mit Google Test gearbeitet.
Ich vermute, dass Google Test zusammen mit dem Anwendungscode compiliert
und zu einem Objekt gelinkt wird. Richtig?
An sich sollte doch -fshort_enums alle enum-Grössen minimieren (sofern
es bei allen Compileraufrufen verwendet wird).
D.h. wird Google Test zusammen mit dem AVR-Code mit MinGW compiliert,
dann sollte -fshort_enums sowohl die enums im AVR-Code als auch die in
Google Test beeinflussen. Richtig?
Warum wirkt dann das Attribut, aber nicht -fshort_enums?
@Theor
Ich habe die Entwicklungsumgebung inclusive dem Google Test von einem
Kollegen bekommen. Das Google Test war bereits als Libraries compiliert,
die ich nur hinzu linke.
Theor schrieb:> Ich vermute, dass Google Test zusammen mit dem Anwendungscode compiliert> und zu einem Objekt gelinkt wird. Richtig?>> An sich sollte doch -fshort_enums alle enum-Grössen minimieren (sofern> es bei allen Compileraufrufen verwendet wird).
Spekulation: Vielleicht benutzt das irgendwelche unter-makefiles die ein
Eigenleben haben und eigene Optionen setzen oder die man separat noch
irgendwie konfigurieren müsste um da was zu ändern.
Bitschubser schrieb:> @Theor> Ich habe die Entwicklungsumgebung inclusive dem Google Test von einem> Kollegen bekommen. Das Google Test war bereits als Libraries compiliert,> die ich nur hinzu linke.
Ah. Verstehe.
Irgendwie hat mich dieser Satz:
Bitschubser schrieb:> [,,,] Oder muss man das Google Test selbst mit dieser Option übersetzen?
angezupft.
D.h. also:
1. Google Test Infrastruktur ist vermutlich ohne -fshort_enum
übersetzt. Ergibt eine Lib oder ein Object-File, das gelinkt wird. (Ich
vermute, dass die Infrastruktur selbst garnicht auf die Daten der
Anwendung zugreift).
2. Das Testprogramm ist sowohl mit als auch ohne -fshort_enum übersetzt
worden.
3. Das Anwendungsprogramm (der AVR-Code) ist sowohl mit als auch ohne
-fshort_enum übersetzt worden.
4. Alle vier möglichen Kombinationen von Punkt 2. und 3. ergeben einen
Segmentation-Fault.
5. ABER: attribute packed angewendet auf eine bestimmte Struktur
beseitigt den Fehler.
Hm. Das scheint mir auffällig widersprüchlich und klärungsbedürftig.
Aber das sind nur meine 5 Cents.
Bitschubser schrieb:> Damit meinte ich das Google Test selbst. Das Testprogramm mit den> Testfällen wird natürlich mit dem zu testenden C-File zusammen> kompiliert.
Naja, dann ist es kein Wunder. Wenn Du eine Compileroption setzt die die
Macht hat das ABI zu ändern dann kannst Du die nicht mehr mit
vorkompilierten Libs zusammenlinken die ohne diese Option kompiliert
wurden.
Ich hab früher auch -fshort-enums verwendet für den selben Zweck wie Du,
bin aber wieder davon abgekommen mit derart schweren Geschützen mit so
einer Reichweite und Zerstörungskraft zu schießen nur um an 2 oder 3
kleinen Stellen was zu erzwingen. Da es ab dem Moment eh
compilerabhängig wird kann ich von 2 Möglichkeiten auch diejenige nehmen
die gezielter wirkt und weniger breit einschlägt.
Was ich außerdem noch immer mache an solchen Stellen ist mit
_Static_assert() zur Kompilezeit das sizeof() der betreffenden structs
zu prüfen um sicherzugehen daß da in der Zukunft absolut nichts mehr
unbemerkt verrutschen kann ohne daß sofort die Alarmglocken losgehen
weil es sich dann weigern wird zu kompilierten.
Bernd K. schrieb:> Bitschubser schrieb:>> [...]>> [...] Wenn Du eine Compileroption setzt die die> Macht hat das ABI zu ändern dann kannst Du die nicht mehr mit> vorkompilierten Libs zusammenlinken die ohne diese Option kompiliert> wurden.>> [...]
Sehe ich ähnlich. Die tatsächlichen Auswirkungen wg. der ABI sollte man
mal untersuchen.
Eine eigene Frage?
Dieser Thread ist über 7 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.