Hallo zusammen Ich nutze Atmel Studio 6.X und habe vor einiger Zeit in Eclipse gesehen, dass dort nicht initialisierte Variablen(in z.B. Klassen) als Compiler-Warning angezeigt werden. Dies ist im Atmel Studio (trotz "-pedentic") nicht der Fall...wie kann ich diese Warnings generieren/anzeigen lassen? Vielen Dank im Voraus NickNack
casud schrieb: > -Wuninitialized ? Habe ich eben unter "Toolchain" -> "AVR/GNU C++ Compiler" -> "Miscellaneous" angehängt, allerdings fehlen die gewünschten warnings immer noch
Es muss auch ein gewisser Grad an Optimierung aktiviert sein, damit der Compiler überhaupt eine Datenflussanalyse macht. Hast du es schon mit -O2 oder -Os probiert? Wenn das auch nicht hilft: Hast du ein kurzes Stück Testcode, bei dem das Problem auftritt? Nick Nack schrieb: > nicht initialisierte Variablen(in z.B. Klassen) Ich bin mir nicht sicher, ob auch Compound-Variablen (also Strukturen, Arrays, Objekte und dergleichen) auf Uninitialisiertheit geprüft werden.
:
Bearbeitet durch Moderator
Yalu X. schrieb: > Es muss auch ein gewisser Grad an Optimierung aktiviert sein, damit der > Compiler überhaupt eine Datenflussanalyse macht. Hast du es schon mit > -O2 oder -Os probiert? Weder "O2" noch "OS" bringen die gewünschten Ausgaben. Dies einer der Aufrufe: avr-g++.exe" -funsigned-char -funsigned-bitfields -I".." -O2 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mrelax -g3 -Wundef -pedantic -mmcu=atmega1284p -c -Wuninitialized -MD -MP -MF "testSuite/TestBase.d" -MT"testSuite/TestBase.d" -MT"testSuite/TestBase.o" -o "testSuite/TestBase.o" "../testSuite/TestBase.cpp" Ich erstelle noch ein kurzes Testprogram für hier
Atmel Studio 6.1 Optimierungslevel: None(-O0) Debug Level: Maximum (-g3) All warnings, warnings as error, pedantic, pedantic warnings as errors other flags: -std=c++11
1 | #include <stdint.h> |
2 | |
3 | int main(void) |
4 | {
|
5 | uint8_t i; |
6 | if(i == 10) |
7 | i = 0; |
8 | }
|
9 | |
10 | // 'i' is used uninitialized in this function [-Werror=uninitialized]
|
Dieser Code schnipsel erzeugt deinen Fehler! Der Fehler kommt natürlich nur wenn du lesend auf eine nicht initialisierte Variable zugreifst. grüße
1 | /*
|
2 | * WarningTest.cpp
|
3 | *
|
4 | * Created: 12.04.2014 23:50:04
|
5 | * Author: NickGame
|
6 | */
|
7 | |
8 | #include <avr/io.h> |
9 | |
10 | class TestClass |
11 | {
|
12 | public:
|
13 | TestClass(); |
14 | ~TestClass(); |
15 | |
16 | bool shouldGenerateWarning; |
17 | bool getTestVar (void); |
18 | protected:
|
19 | |
20 | private:
|
21 | };
|
22 | |
23 | TestClass::TestClass() |
24 | {
|
25 | // here should variable "shouldGenerateWarning" be initialized
|
26 | }
|
27 | |
28 | TestClass::~TestClass() |
29 | {
|
30 | |
31 | }
|
32 | |
33 | bool TestClass::getTestVar( void ) |
34 | {
|
35 | return this->shouldGenerateWarning; |
36 | }
|
37 | |
38 | TestClass test; |
39 | int main(void) |
40 | {
|
41 | while(1) |
42 | {
|
43 | volatile bool testReadVar = test.getTestVar(); |
44 | }
|
45 | }
|
:
Bearbeitet durch User
Bei Klassenvariablen/structs erscheint diese warnung nicht (zumindestens kann ich sie dort nicht forcieren)! Das heist allerdings nicht, das die variable initialisiert wird! (wie man im simulator/debugger ja überprüfen kann)
Nick Nack schrieb: > return this->shouldGenerateWarning; Woher soll der Compiler wissen dass an dieser Stelle "shouldGenerateWarning" nicht initialisiert ist? GCC ist schon ziemlich schlau, aber über mehrere Funktionen weg den Ablauf zu analysieren ob eine Variable zuvor initialisiert wurde, das kann er nicht... Nick Nack schrieb: > TestClass::TestClass() > { > // here should variable "shouldGenerateWarning" be initialized Nö, muss gar nicht. In nicht-"constexpr"-Konstruktoren kann man Member-Variablen von built-in typen sehr wohl uninitialisiert lassen, was auch sehr oft gemacht wird. Schau aber mal hier: http://stackoverflow.com/questions/2099692/easy-way-find-uninitialized-member-variables/2911740#2911740 Kaj schrieb: > Das heist allerdings nicht, das die > variable initialisiert wird! (wie man im simulator/debugger ja > überprüfen kann) Wird sie nicht, nicht-statische und nicht-globale Variablen mit built-in Typen werden nicht automatisch initialisiert, steht dann irgendein zufälliger Unsinn drin.
Erstens hat deine Variable einen Konstruktor. Zweitens ist deine Variable global -- solche Variablen sind IMMER initialisiert.
Um diese Variable geht es aber nicht, sondern um die Member-Variable, die ist weder global noch hat sie einen Konstruktor.
Sie ist aber Element einer globalen Variable und wird damit automatisch mit false initialisiert. Insofern ist das Beispiel etwas schlecht gewählt. Man könnte aber die Variable test einfach lokal (und nicht static) in main definieren. Dann bleibt das Element shouldGenerateWarning tatsächlich uninitialisiert, und der Compiler warnt aus den bereits genannten Gründen trotzdem nicht. Vielleicht ist da das eine oder andere statische Analysetool etwas gründlicher.
Yalu X. schrieb: > Vielleicht ist da das eine oder andere statische Analysetool etwas > gründlicher. Man kann immer Fälle konstruieren, in denen ein Analysetool, welches nicht den kompletten Code in allen Source Code Files analysiert, eine fehlende Initialisierung nicht detektieren kann. Genau deshalb bin ich kein Freund von blindem Vertrauen in derartige Warnungen. Wenn sie kommen, ist es ein nettes Hilfsmittel. Aber in erster Linie ist der Programmierer selbst dafür verantwortlich, dass alles korrekt abläuft. Genau deshalb verdienen wir unsere Brötchen, weil wir auch auf solche Sachen ein Auge werfen und uns darum kümmern und uns nicht darauf verlassen, dass ein Compiler alles findet.
:
Bearbeitet durch User
Yalu X. schrieb: > Man könnte aber die Variable test einfach lokal (und nicht static) in > main definieren. Dann bleibt das Element shouldGenerateWarning > tatsächlich uninitialisiert, und der Compiler warnt aus den bereits > genannten Gründen trotzdem nicht. Mein GCC warnt aber schon:
1 | tmp:1013> cat foo.cpp |
2 | struct Hugo { |
3 | Hugo() {} |
4 | ~Hugo() {} |
5 | int var; |
6 | int get() { |
7 | return this->var; |
8 | }
|
9 | };
|
10 | |
11 | int main() |
12 | {
|
13 | Hugo h; |
14 | volatile int frotz = h.get(); |
15 | }
|
16 | tmp:1014> g++ -Wall -Os foo.cpp |
17 | foo.cpp: In function 'int main()': |
18 | foo.cpp:13: warning: unused variable 'frotz' |
19 | foo.cpp:13: warning: 'h$var' is used uninitialized in this function |
und dabei ist der nicht mal der modernste:
1 | tmp:1015> gcc -v |
2 | Using built-in specs. |
3 | Target: x86_64-suse-linux |
4 | Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.1.2 --enable-ssp --disable-libssp --disable-libgcj --with-slibdir=/lib64 --with-system-zlib --enable-shared --enable-__cxa_atexit --enable-libstdcxx-allocator=new --program-suffix=-4.1 --enable-version-specific-runtime-libs --without-system-libunwind --with-cpu=generic --host=x86_64-suse-linux |
5 | Thread model: posix |
6 | gcc version 4.1.2 20061115 (prerelease) (SUSE Linux) |
tictactoe schrieb: > Mein GCC warnt aber schon: Dann teil das mal alles in ein paar nette Files auf, so wie man das in der Praxis haben wird, wenn die Projekt mal ein bißchen größer werden. hugo.h
1 | struct Hugo { |
2 | Hugo() |
3 | ~Hugo() |
4 | |
5 | int var; |
6 | int get() { |
7 | return this->var; |
8 | }
|
9 | };
|
hugo.cpp
1 | #include "hugo.h" |
2 | |
3 | Hugo::Hugo() |
4 | {
|
5 | }
|
6 | |
7 | Hugo::~Hugo() |
8 | {
|
9 | }
|
main.cpp
1 | #include "hugo.h" |
2 | |
3 | int main() |
4 | {
|
5 | Hugo h; |
6 | volatile int frotz = h.get(); |
7 | }
|
warnt er jetzt immer noch?
:
Bearbeitet durch User
tictactoe schrieb: > Mein GCC warnt aber schon: Mist, ich habe wohl meinen eigenen Beitrag nicht gelesen: Yalu X. schrieb: > Es muss auch ein gewisser Grad an Optimierung aktiviert sein, damit der > Compiler überhaupt eine Datenflussanalyse macht. Hast du es schon mit > -O2 oder -Os probiert? Ja, mit -O2 oder -Os warnt auch mein GCC :) Karl Heinz schrieb: > Dann teil das mal alles in ein paar nette Files auf, so wie man das in > der Praxis haben wird, wenn die Projekt mal ein bißchen größer werden. > > ... > > warnt er jetzt immer noch? Wie zu erwarten war, weil der Compiler immer nur eine cpp-Datei auf einmal anschaut: Nein. Hier hätte aber ein ordentliches Analysetool (frag mich jetzt nicht, welches) eine gute Chance gehabt, den Fehler zu finden, weil diese Tools i.Allg. den Datenfluss dateiübergreifend verfolgen. Aber auch das beste Analysetool stößt irgendwann an seine Grenzen, schon alleine deswegen, weil die Frage der Verwendung einer uninitialisierten Variable nicht allgemein entscheidbar ist. Auch wenn die automatisierte Fehlersuche nicht perfekt ist, bedeutet jeder vom Programmierer übersehene, aber vom Tool entdeckte Fehler am Ende einen Fehler weniger. PS: Will man uninitialisierte Variablen garantiert ausschließen, nimmt man einfach eine funktionale Programmiersprache anstelle von einer imperativen :)
Karl Heinz schrieb: > Dann teil das mal alles in ein paar nette Files auf, so wie man das in > der Praxis haben wird, wenn die Projekt mal ein bißchen größer werden. > warnt er jetzt immer noch? Nö, wie denn auch :-) Nimm mal Konstruktor und Destruktor raus (die tun ja eh nichts), dann ist die Warnung wieder da. Aber das zeigt nur, was du schon geschrieben hast: Karl Heinz schrieb: > Aber in > erster Linie ist der Programmierer selbst dafür verantwortlich, dass > alles korrekt abläuft. Genau deshalb verdienen wir unsere Brötchen... Wenn man schon eine Konstruktor schreibt, dann soll der auch tun, was er verspricht.
tictactoe schrieb: > Karl Heinz schrieb: >> Dann teil das mal alles in ein paar nette Files auf, so wie man das in >> der Praxis haben wird, wenn die Projekt mal ein bißchen größer werden. > >> warnt er jetzt immer noch? > > Nö, wie denn auch :-) Genau das ist der springende Punkt. Ich hab nichts gegen die Warnungen. Die sind durchaus sinnvoll. Was aber nicht sinnvoll ist: sich darauf zu verlassen, dass uninitialisierte Variablen vom Compiler angemerkt werden würden. Also den Umkehrschluss zu machen: Ich hab keine Warnung, daher hab ich keine uninitialisierte Variablen. > Karl Heinz schrieb: >> Aber in >> erster Linie ist der Programmierer selbst dafür verantwortlich, dass >> alles korrekt abläuft. Genau deshalb verdienen wir unsere Brötchen... > > Wenn man schon eine Konstruktor schreibt, dann soll der auch tun, was er > verspricht. Na komm. So viel Phantasie wirst du ja wohl noch haben, dass ich in diese struct noch 5 andere Dinge reinpacken könnte, die dann sehr wohl eine Behandlung in einem Konstruktor benötigen würden. Das sollte eigentlich klar sein, dass ich ein Beispiel soweit abspecke, um den Punkt herauszuarbeiten und zu diskutieren auf den ich raus will, ohne noch 8 andere Nebenschauplätze zu haben. Der Punkt ist, dass ein Compiler nicht alle uninitialisierten Variablen feststellen kann. Woraus folgt, dass ein blindes Verlassen auf die Warnung bzw. deren Nichterscheinen, tödlich sein kann. Etwas das gerade Neulinge gerne übersehen.
:
Bearbeitet durch User
Karl Heinz schrieb: >> Wenn man schon eine Konstruktor schreibt, dann soll der auch tun, was er >> verspricht. > > Na komm. So viel Phantasie wirst du ja wohl noch haben, dass ich in > diese struct noch 5 andere Dinge reinpacken könnte, die dann sehr wohl > eine Behandlung in einem Konstruktor benötigen würden. Er meinte das etwas anders: Einer, der seine Brötchen mit Programmieren verdient, wird einen Konstruktor so schreiben, das der das Objekt auch wirklich konstruiert, wozu insbesondere die Initialisierung gehört. Dann stellt sich die Frage nach uninitialisierten Membervariablen gar nicht erst.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.