Chapter 7. Common Pitfalls

This chapter contains the following major sections:

Problems Involving C Linkage

One of the most common problems you may encounter occurs when you link your C++ programs to C code (such as C libraries). This section contains many of the most typical problems you run into in that situation.

  • Unexpected undefined symbols. You may see the following error message from the link-editor:

    Unresolved:  foo(int, char*)
    

    The presence of the prototype in this message indicates that this is a C++ function. Frequently this means not that the function foo is undefined, but that it is defined in a C object file or library, and the C++ declaration is missing an extern “C” linkage specification.

  • Inconsistent linkage. You may see the following error message from the C++ front end (fecc):

    “afile.c”, line 37: error (1311): linkage specification is incomplete with previous foo (declared at line 17)
    

    This means that two declarations for foo() were found with the same prototype, the first outside an extern “C” specification and the second inside. For example, you may have the following code, all in one compilation unit:

    void foo(int, char*);
    ......
    extern "C" {  void foo(int, char*);  }
    

    Frequently these two declarations come from different header files.

  • A “Two ... with c linkage” error. For example, you may see the following error message from the C++ front end (edgcpfe):

    “afile.C”, line 37: error (3419): more than one instance of overloaded function “foo” has “C” linkage.
    

    This indicates that two declarations for foo() were found within extern “C” specifications but with different prototypes. Typically this happens when a function is declared in two header files with the wrong prototype in one of them, or when a function already declared in an included header file is redeclared incorrectly.

Problems With Order of Specification of Libraries

This section covers two typical problems you may encounter when you specify the order of your libraries.

  • Inability to use the Silicon Graphics fast malloc routines, malloc(3x).

    A related problem occurs with a command such as the following:

    CC foo.c++ -lmalloc
    

    The command mysteriously fails to use the “fast” libmalloc.a versions of malloc() and free(). Here again the order of libraries is

    -lmalloc -lC -lc 
    

    At the time ld processes libmalloc.a, there are no undefined references to malloc() and free() (unless explicitly referenced from foo.c++). Only when new and delete are picked up from libC.a are malloc() and free() required, and then it is too late: their references have already been resolved from libc.a instead of libmalloc.a. Again, once the problem is recognized, the solution is easy. Just change the command to the following:

    CC foo.c++ -lC -lmalloc
    

  • Mixing stdio and iostreams.

    If you mix iostream output using cout with stdio output using printf, and you are not careful about flushing the output buffers, you may see unexpected results. For example, consider the following program:

    #include <stdio.h> 
    #include <ostream.h> 
    main() {
      cout << "cout1\n";
      printf("printf1\n");
      cout << "cout2\n";
      printf("printf2\n");
     }
    

    This code produces the following output:

    printf1 
    printf2 
    cout1 
    cout2
    

    This is because cout and printf use distinct buffers, and insertion of a newline into cout does not flush the buffer. To flush the buffer, you can insert the manipulator flush into the stream in the following way:

    cout << "cout1\n" << flush;
    

    You can also use the manipulator endl to insert a newline and flush as follows:

    cout << "cout1" << endl;
    

    On the other hand, consider the following program

    main() {
      cout << "cout1 " << flush;
      printf("printf1 ");
      cout << "cout2 " << flush;
     }
    

    This code produces the output

    cout1 cout2 printf1
    

    This is because the buffer for printf is not flushed until the program terminates. Here you need to call fflush after the call to printf as follows:

    fflush(stdout);
    

    This generates the following “expected” output:

    cout1 printf1 cout2
    

    If you wish to avoid explicitly flushing the buffer, you may insert the following code before performing any input/output:

    ios::sync_with_stdio();