Warnings: Compiling

The level of warnings generated by the gcc compiler has been set to be more pedantic than the default [1]. While this introduces some pain to writing code that compiles without warnings it helps catch mistakes and makes for more portable code.

This document is an attempt to give examples of some of the most common warning messages and suggest remedies.

unused parameter

Example: /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx: In member function `void MyClass::Print(const Option_t* option) const': /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx:394: warning: unused parameter `const Option_t* option' This will probably be the most common warning. It is generated when the implementation of a class method fails to use one of the parameters. Often it is quite legitimate to not make use of a parameter because the method's signature is derived from overriding a base class's method and the argument is irrelevant for the particular usage. But it can be an important reminder of potential logic mistakes -- so one should seriously evaluate whether it makes sense for a particular method to not use all of the supplied arguments.

Eliminating the warning is trival; simply comment out the naming of the argument in the implementation file (.cxx), e.g.:

void MyClass::Print(const Option_t* option) const becomes: void MyClass::Print(const Option_t* /* option */) const

was hidden by

Example: In file included from /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx:3: /home/minlib/ROOT_CVS/GCC_3_2/include/TObject.h:143: warning: `virtual void TObject::Print(const Option_t*) const' was hidden /home/minlib/minossoft/releases/development/include/MyPackage/MyClass.h:23: warning: by `void MyClass::Print(const Option_t*)' This warning arises because out of two common cases: The example above falls into the first category. If one looks carefully one discovers that the MyClass version is a non-const method and thus the attempted overriding wasn't acheived. This can be remedeed by bringing the signatures into accord.

An example of the second category might be declaring MyClass::Clear() while TObject has a method Clear(const Option_t*). Here it might be worthwhile to morph the new declaration to match the base class while retaining the illusion of the old behaviour. In this case one could declare, in the header, the method as:

Clear(const Option_t* option="") By supplying a default value no current arg-less usage must be changed.

Question for the C++ language lawyer:

If the base class B has signatures and the derived class D declares and implements and one has a D object:

argument given ... after previous specification ...

Example: /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx:200: warning: default argument given for parameter 1 of `void MyClass::Trace(const char* = "") const' /home/minlib/minossoft/releases/development/include/MyPackage/MyClass.h:42: warning: after previous specification in `virtual void MyClass::Trace(const char* = "") const' This occurs when the implementation file (.cxx) specifies a default argument. Only header files (.h) should ever give a default value.

This can also occur if the header is included twice and not protected against the second parsing via the usual mechanism:

#ifndef THISHEADERFILE_H #define THISHEADERFILE_H (header information goes here) #endif This protection is a required by the coding conventions.

conversion from string const to char*

Example: /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx: In constructor `MyClass::MyMethod(MyObject*)': /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx:85: warning: deprecated conversion from string constant to `char*' This comes from the assignment of a string constant (or literal) to a non-const char*. A literal is text within double-quotes ("). This is generally allowed by the older standard, but is dangerous because common literals might be shared and thus if one were to modify the value others variables would magically change, e.g.: const char* mystring = "xyzzy"; char* another = "xyzzy"; // might share address w/ 'mystring' strcpy(another,"ABCDE"); // in principle modifying a non-const is okay cout << mystring << endl; // suprisingly might be 'ABCDE' Generally the simple fix is simply to always make the assignment of a literal to a const char*. Sometimes when passing a literal to a method/function one gets this warning. In this case one has two kosher options (excluding const_cast<char*>()):

ISO C++ forbids variable-size array name

Example: /home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx: In member function `void MyClass::Doit(int)': /home/minlib/minossoft/packages/Monitoring/HEAD/MyClass.cxx:782: warning: ISO C++ forbids variable-size array `abc' This warning points to the usage of a GNU gcc extension is a serious portablity problem. Technically the code: void MyClass::Doit(int n) { float abc[n]; .... abc[i] = 3.1415 ... } is illegal, because the value of n is not known at compile time. GNU gcc provides an extension for automatic arrays that allocate based on run time values; but relying on these makes the code out of compliance with the standard.

If the value of n isn't known until run-time then one can bring the code into compliance by either converting to performing the allocation/deallocation explicitly on conventions arrays, or by using STL containers.(e.g. std::vector).

void MyClass::Doit(int n) { float *abc = new float[n]; .... abc[i] = 3.1415 .... delete [] abc; // don't forget to delete with [] } #include <vector> void MyClass::Doit(int n) { std::vector<float> abc(n); // note ()'s, not [] .... abc[i] = 3.1415 ... }

control reaches end of non-void function

Example: home/minlib/minossoft/packages/MyPackage/HEAD/MyClass.cxx: In member function `Float_t MyClass::MyMethod(float)': /home/minlib/minossoft/packages/MyPackage/HEAD/MyMethod.cxx:160: warning: control reaches end of non-void function These are caused when there is some way for a function declared to return a value (i.e. non-void), but doesn't, e.g.: Float_t MyClass::MyMethod(float x) { if ( x >= 0 ) return 100.; } if x is negative the function ends but no value is explicitly returned. What generally happens is that the caller of the function will get whatever garbage was on the stack, which can lead to unpredictable results. Users should ensure that non-void function return a meaningful value under all conditions.


[1]: The additional flags placed on the g++ command line are:
-Wall Issue warnings for conditions which pertain to usage that we [gcc] recommend avoiding and that we believe is easy to avoid, even in conjunction with macros.
-pedantic Issue all the warnings demanded by strict ANSI standard C; [generate warnings for] all programs that use forbidden extensions.
-W Print extra warning messages for these events:
  • An unsigned value is compared against zero with > or <=.
  • An expression-statement or the left-hand side of a comma expression contains no side effects. To suppress the warning, cast the unused expression to void. For example, an expression such as x[i,j] will cause a warning, but x[(void)i,j] will not.
  • A nonvolatile automatic variable might be changed by a call to longjmp. These warnings are possible only in optimizing compilation.
-Wno-long-long Do not warn if long long type is used. (Takes this out of those enabled by -pedantic).
-Wwrite-strings Give string constants the type const char[length] so that copying the address of one into a non-const char * pointer will get a warning. These warnings will help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it will just be a nuisance; this is why we did not make -Wall request these warnings.
-Winline Warn if a function can not be inlined, and either it was declared as inline, or else the -finline-functions option was given. [RWH: I'm not sure this works]
-Woverloaded-virtual In a derived class, the definitions of virtual functions must match the type signature of a virtual function declared in the base class. Use this option to request warnings when a derived class declares a function that may be an erroneous attempt to define a virtual function: that is, warn when a function with the same name as a virtual function in the base class, but with a type signature that doesn't match any virtual functions from the base class.

[2]: A particular function has a signature that is defined by the function's name; its parameter types (in order); and for class method whether it is const (i.e.: can act on const objects because it does not modify any data members; this is signified by a trailing const after the argument list).


Contact: Robert Hatcher (<rhatcher@fnal.gov>)