[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10. Known Causes of Trouble with GCC

This section describes known problems that affect users of GCC. Most of these are not GCC bugs per se--if they were, we would fix them. But the result for a user may be like the result of a bug.

Some of these problems are due to bugs in other software, some are missing features that are too much work to add, and some are places where people's opinions differ as to what is best.

10.1 Actual Bugs We Haven't Fixed Yet  Bugs we will fix later.
10.2 Cross-Compiler Problems  Common problems of cross compiling with GCC.
10.3 Interoperation  Problems using GCC with other compilers, and with certain linkers, assemblers and debuggers.
10.4 Problems Compiling Certain Programs  Problems compiling certain programs.
10.5 Incompatibilities of GCC  GCC is incompatible with traditional C.
10.6 Fixed Header Files  GCC uses corrected versions of system header files. This is necessary, but doesn't always work smoothly.
10.7 Standard Libraries  GCC uses the system C library, which might not be compliant with the ISO C standard.
10.8 Disappointments and Misunderstandings  Regrettable things we can't change, but not quite bugs.
10.9 Common Misunderstandings with GNU C++  Common misunderstandings with GNU C++.
10.10 Caveats of using protoize  Things to watch out for when using protoize.
10.11 Certain Changes We Don't Want to Make  Things we think are right, but some others disagree.
10.12 Warning Messages and Error Messages  Which problems in your code get warnings, and which get errors.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.1 Actual Bugs We Haven't Fixed Yet


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.2 Cross-Compiler Problems

You may run into problems with cross compilation on certain machines, for several reasons.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.3 Interoperation

This section lists various difficulties encountered in using GCC together with other compilers or with the assemblers, linkers, libraries and debuggers on certain systems.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.4 Problems Compiling Certain Programs

Certain programs have problems compiling.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.5 Incompatibilities of GCC

There are several noteworthy incompatibilities between GNU C and K&R (non-ISO) versions of C.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.6 Fixed Header Files

GCC needs to install corrected versions of some system header files. This is because most target systems have some header files that won't work with GCC unless they are changed. Some have bugs, some are incompatible with ISO C, and some depend on special features of other compilers.

Installing GCC automatically creates and installs the fixed header files, by running a program called fixincludes (or for certain targets an alternative such as fixinc.svr4). Normally, you don't need to pay attention to this. But there are cases where it doesn't do the right thing automatically.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.7 Standard Libraries

GCC by itself attempts to be a conforming freestanding implementation. See section Language Standards Supported by GCC, for details of what this means. Beyond the library facilities required of such an implementation, the rest of the C library is supplied by the vendor of the operating system. If that C library doesn't conform to the C standards, then your programs might get warnings (especially when using `-Wall') that you don't expect.

For example, the sprintf function on SunOS 4.1.3 returns char * while the C standard says that sprintf returns an int. The fixincludes program could make the prototype for this function match the Standard, but that would be wrong, since the function will still return char *.

If you need a Standard compliant library, then you need to find one, as GCC does not provide one. The GNU C library (called glibc) provides ISO C, POSIX, BSD, SystemV and X/Open compatibility for GNU/Linux and HURD-based GNU systems; no recent version of it supports other systems, though some very old versions did. Version 2.2 of the GNU C library includes nearly complete C99 support. You could also ask your operating system vendor if newer libraries are available.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.8 Disappointments and Misunderstandings

These problems are perhaps regrettable, but we don't know any practical way around them.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.9 Common Misunderstandings with GNU C++

C++ is a complex language and an evolving one, and its standard definition (the ISO C++ standard) was only recently completed. As a result, your C++ compiler may occasionally surprise you, even when its behavior is correct. This section discusses some areas that frequently give rise to questions of this sort.

10.9.1 Declare and Define Static Members  Static member declarations are not definitions
10.9.2 Name lookup, templates, and accessing members of base classes  
10.9.3 Temporaries May Vanish Before You Expect  Temporaries may vanish before you expect
10.9.4 Implicit Copy-Assignment for Virtual Bases  Copy Assignment operators copy virtual bases twice


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.9.1 Declare and Define Static Members

When a class has static data members, it is not enough to declare the static member; you must also define it. For example:

 
class Foo
{
  ...
  void method();
  static int bar;
};

This declaration only establishes that the class Foo has an int named Foo::bar, and a member function named Foo::method. But you still need to define both method and bar elsewhere. According to the ISO standard, you must supply an initializer in one (and only one) source file, such as:

 
int Foo::bar = 0;

Other C++ compilers may not correctly implement the standard behavior. As a result, when you switch to g++ from one of these compilers, you may discover that a program that appeared to work correctly in fact does not conform to the standard: g++ reports as undefined symbols any static data members that lack definitions.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.9.2 Name lookup, templates, and accessing members of base classes

The C++ standard prescribes that all names that are not dependent on template parameters are bound to their present definitions when parsing a template function or class.(5) Only names that are dependent are looked up at the point of instantiation. For example, consider

 
  void foo(double);

  struct A {
    template <typename T>
    void f () {
      foo (1);        // 1
      int i = N;      // 2
      T t;
      t.bar();        // 3
      foo (t);        // 4
    }

    static const int N;
  };

Here, the names foo and N appear in a context that does not depend on the type of T. The compiler will thus require that they are defined in the context of use in the template, not only before the point of instantiation, and will here use ::foo(double) and A::N, respectively. In particular, it will convert the integer value to a double when passing it to ::foo(double).

Conversely, bar and the call to foo in the fourth marked line are used in contexts that do depend on the type of T, so they are only looked up at the point of instantiation, and you can provide declarations for them after declaring the template, but before instantiating it. In particular, if you instantiate A::f<int>, the last line will call an overloaded ::foo(int) if one was provided, even if after the declaration of struct A.

This distinction between lookup of dependent and non-dependent names is called two-stage (or dependent) name lookup. G++ implements it since version 3.4.

Two-stage name lookup sometimes leads to situations with behavior different from non-template codes. The most common is probably this:

 
  template <typename T> struct Base {
    int i;
  };

  template <typename T> struct Derived : public Base<T> {
    int get_i() { return i; }
  };

In get_i(), i is not used in a dependent context, so the compiler will look for a name declared at the enclosing namespace scope (which is the global scope here). It will not look into the base class, since that is dependent and you may declare specializations of Base even after declaring Derived, so the compiler can't really know what i would refer to. If there is no global variable i, then you will get an error message.

In order to make it clear that you want the member of the base class, you need to defer lookup until instantiation time, at which the base class is known. For this, you need to access i in a dependent context, by either using this->i (remember that this is of type Derived<T>*, so is obviously dependent), or using Base<T>::i. Alternatively, Base<T>::i might be brought into scope by a using-declaration.

Another, similar example involves calling member functions of a base class:

 
  template <typename T> struct Base {
      int f();
  };

  template <typename T> struct Derived : Base<T> {
      int g() { return f(); };
  };

Again, the call to f() is not dependent on template arguments (there are no arguments that depend on the type T, and it is also not otherwise specified that the call should be in a dependent context). Thus a global declaration of such a function must be available, since the one in the base class is not visible until instantiation time. The compiler will consequently produce the following error message:

 
  x.cc: In member function `int Derived<T>::g()':
  x.cc:6: error: there are no arguments to `f' that depend on a template
     parameter, so a declaration of `f' must be available
  x.cc:6: error: (if you use `-fpermissive', G++ will accept your code, but
     allowing the use of an undeclared name is deprecated)

To make the code valid either use this->f(), or Base<T>::f(). Using the -fpermissive flag will also let the compiler accept the code, by marking all function calls for which no declaration is visible at the time of definition of the template for later lookup at instantiation time, as if it were a dependent call. We do not recommend using -fpermissive to work around invalid code, and it will also only catch cases where functions in base classes are called, not where variables in base classes are used (as in the example above).

Note that some compilers (including G++ versions prior to 3.4) get these examples wrong and accept above code without an error. Those compilers do not implement two-stage name lookup correctly.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.9.3 Temporaries May Vanish Before You Expect

It is dangerous to use pointers or references to portions of a temporary object. The compiler may very well delete the object before you expect it to, leaving a pointer to garbage. The most common place where this problem crops up is in classes like string classes, especially ones that define a conversion function to type char * or const char *---which is one reason why the standard string class requires you to call the c_str member function. However, any class that returns a pointer to some internal structure is potentially subject to this problem.

For example, a program may use a function strfunc that returns string objects, and another function charfunc that operates on pointers to char:

 
string strfunc ();
void charfunc (const char *);

void
f ()
{
  const char *p = strfunc().c_str();
  ...
  charfunc (p);
  ...
  charfunc (p);
}

In this situation, it may seem reasonable to save a pointer to the C string returned by the c_str member function and use that rather than call c_str repeatedly. However, the temporary string created by the call to strfunc is destroyed after p is initialized, at which point p is left pointing to freed memory.

Code like this may run successfully under some other compilers, particularly obsolete cfront-based compilers that delete temporaries along with normal local variables. However, the GNU C++ behavior is standard-conforming, so if your program depends on late destruction of temporaries it is not portable.

The safe way to write such code is to give the temporary a name, which forces it to remain until the end of the scope of the name. For example:

 
const string& tmp = strfunc ();
charfunc (tmp.c_str ());


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.9.4 Implicit Copy-Assignment for Virtual Bases

When a base class is virtual, only one subobject of the base class belongs to each full object. Also, the constructors and destructors are invoked only once, and called from the most-derived class. However, such objects behave unspecified when being assigned. For example:

 
struct Base{
  char *name;
  Base(char *n) : name(strdup(n)){}
  Base& operator= (const Base& other){
   free (name);
   name = strdup (other.name);
  }
};

struct A:virtual Base{
  int val;
  A():Base("A"){}
};

struct B:virtual Base{
  int bval;
  B():Base("B"){}
};

struct Derived:public A, public B{
  Derived():Base("Derived"){}
};

void func(Derived &d1, Derived &d2)
{
  d1 = d2;
}

The C++ standard specifies that `Base::Base' is only called once when constructing or copy-constructing a Derived object. It is unspecified whether `Base::operator=' is called more than once when the implicit copy-assignment for Derived objects is invoked (as it is inside `func' in the example).

G++ implements the "intuitive" algorithm for copy-assignment: assign all direct bases, then assign all members. In that algorithm, the virtual base subobject can be encountered more than once. In the example, copying proceeds in the following order: `val', `name' (via strdup), `bval', and `name' again.

If application code relies on copy-assignment, a user-defined copy-assignment operator removes any uncertainties. With such an operator, the application can define whether and how the virtual base subobject is assigned.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.10 Caveats of using protoize

The conversion programs protoize and unprotoize can sometimes change a source file in a way that won't work unless you rearrange it.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.11 Certain Changes We Don't Want to Make

This section lists changes that people frequently request, but which we do not make because we think GCC is better without them.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.12 Warning Messages and Error Messages

The GNU compiler can produce two kinds of diagnostics: errors and warnings. Each kind has a different purpose:

Warnings may indicate danger points where you should check to make sure that your program really does what you intend; or the use of obsolete features; or the use of nonstandard features of GNU C or C++. Many warnings are issued only if you ask for them, with one of the `-W' options (for instance, `-Wall' requests a variety of useful warnings).

GCC always tries to compile your program if possible; it never gratuitously rejects a program whose meaning is clear merely because (for instance) it fails to conform to a standard. In some cases, however, the C and C++ standards specify that certain extensions are forbidden, and a diagnostic must be issued by a conforming compiler. The `-pedantic' option tells GCC to issue warnings in such cases; `-pedantic-errors' says to make them errors instead. This does not mean that all non-ISO constructs get warnings or errors.

See section Options to Request or Suppress Warnings, for more detail on these and related command-line options.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Mail Server on June, 15 2005 using texi2html