Forum: Compiler & IDEs Compiler-Warnings für nicht initialisierte Variablen EINschalten


von Nick Nack (Gast)


Lesenswert?

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

von casud (Gast)


Lesenswert?

-Wuninitialized ?

von Nick Nack (Gast)


Lesenswert?

casud schrieb:
> -Wuninitialized ?

Habe ich eben unter "Toolchain" -> "AVR/GNU C++ Compiler" -> 
"Miscellaneous" angehängt, allerdings fehlen die gewünschten warnings 
immer noch

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
von Nick Nack (Gast)


Lesenswert?

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

von Kaj (Gast)


Lesenswert?

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

von Nick Nack (Gast)


Lesenswert?

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
von Kaj (Gast)


Lesenswert?

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)

von Dr. Sommer (Gast)


Lesenswert?

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.

von tictactoe (Gast)


Lesenswert?

Erstens hat deine Variable einen Konstruktor. Zweitens ist deine 
Variable global -- solche Variablen sind IMMER initialisiert.

von Dr. Sommer (Gast)


Lesenswert?

Um diese Variable geht es aber nicht, sondern um die Member-Variable, 
die ist weder global noch hat sie einen Konstruktor.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von tictactoe (Gast)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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
von Yalu X. (yalu) (Moderator)


Lesenswert?

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 :)

von tictactoe (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
von Yalu X. (yalu) (Moderator)


Lesenswert?

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
Noch kein Account? Hier anmelden.