Click here to load reader

CS 213 Fall 1998 Namespaces Inline functions Preprocessing Compiling Name mangling Linking

  • View

  • Download

Embed Size (px)


CS 213 Fall 1998 Namespaces Inline functions Preprocessing Compiling Name mangling Linking. Namespaces. Suppose we purchase a library of cartographic tools from the Acme Geographic company. These tools are written as a collection of C++ classes: map, legend, road, city, ... - PowerPoint PPT Presentation

Text of CS 213 Fall 1998 Namespaces Inline functions Preprocessing Compiling Name mangling Linking

  • CS 213Fall 1998

    NamespacesInline functionsPreprocessingCompilingName manglingLinking

  • Namespaces

    Suppose we purchase a library of cartographic tools from the Acme Geographic company. These tools are written as a collection of C++ classes:

    map, legend, road, city, ...

    Also, say we want to use container classes from STL:

    string, list, vector, map, ...

    Theres a problem: when we type map, does this refer to Acme Geographics map class, or STLs map class?

  • To deal with this, Acme Geographic and STL can declare their classes, functions, and variables in separate namespaces:

    // STL header file:namespace std { class string {...}; template class vector {...}; template class list {...}; template class map {...}; ...}// Acme Geographic header file:namespace AcmeGeo { class map {...}; class legend {...}; ...}

  • namespace std { class string {...}; template class vector {...}; template class list {...}; template class map {...}; ...}namespace AcmeGeo { class map {...}; class legend {...}; ...}

    To use classes, functions, or variables declared in a namespace, a program gives the namespace name followed by a :: and the name of the class, function or variable:

    AcmeGeo::map ithacaStreetMap;std::map ithacaPhoneNumbers;

  • Names can be added to a namespace in many different places. For instance, STL names are spread over many different header files:

    // string header file:namespace std { class string {...};}

    // list header file:namespace std { template class list {...};}

    // map header file:namespace std { template class map {...};}

  • A program can import a name into a scope with a using declaration:

    #include #include #include AcmeGeo.h

    void main() { using std::string; using AcmeGeo::map;

    map ithacaStreetMap; std::map ithacaPhoneNumbers; ...}

    Within main(), string refers to std::string, and map refers to AcmeGeo::map.

  • It is also possible to import all the names from an entire namespace at once, with a using directive:

    void main() { using std::string; using namespace AcmeGeo;

    map ithacaStreetMap; std::map ithacaPhoneNumbers; ...}

  • Namespaces are a fairly new feature in C++. Not all compilers implement them correctly yet. In addition, a good deal of C++ code was written before namespaces were part of the language:

    // Old-style C++ code#include void main() { cout

  • In other words,


    is equivalent to

    #include using namespace std;

    Officially, the old .h standard library header files (iostream.h, stdlib.h, etc.) are deprecated. The new header files the .h in the older header files, while even older header files from C drop the .h and add a c:

    iostream.h -> iostreamfstream.h -> fstreamstdlib.h -> cstdlibctype.h -> cctype

  • Inline Functions

    To avoid the cost of a function call, functions may be defined to be inline:

    inline double square(double x) {return x * x;}

    An inline functions code is replicated at each point in the program where it is called. This can enable many optimizations. Consider the following:

    double f(double y) {return y * square(3);}

    Because square is declared inline, most compilers will optimize y * square(3) to y * 9 at compile-time.

  • Watch out, though: only small functions should be declared inline. If you make too many big functions inline, the size of your executable code will grow. Because large executables lead to bad cache usage and even paging, excessive inlining may make your program slower, rather than faster.

  • When you declare the implementation of a function inside the definition of a class, the function is automatically considered inline. So

    class Foo { ... int f(int x) {return x + 1;}}

    is equivalent to:

    class Foo { ... int f(int x);}inline int Foo::f(int x) {return x + 1;}

  • Lets look at how a collection of header files and source files are turned into an executing program in memory:

    I will assume that header files have the suffix .h, while regular source files have the suffix .cpp. Other suffixes (.C, .cxx, .cc) are also common.memory

  • There are 4 steps involved:

    preprocessing: the .cpp files are preprocessed by a macro processor. The macro processor handles #include, #ifdef, #define, etc.

    compiling: the preprocessed .cpp files (called translation units) are compiled into object files.

    linking: the object files are linked together to form a single executable program.

    loading: the executable program is loaded into memory and executed.AcmeGeo.hmacro processorlinkercompilerloader001011000101memoryAcmeGeo.cppithaca.cppmapstringAcmeGeotranslation unitithacatranslation unitAcmeGeo.objithaca.objithaca.exe

  • The preprocessor

    The preprocessor (or macro processor) interprets directives and macros in a C or C++ file. Typical preprocessor directives are:


  • The most important directive in C++ is the #include directive. When the preprocessor sees a #include directive, it substitutes the contents of the included file into the file that is being preprocessed:preprocessstringmapAcmeGeo.h

  • #include is a fairly blunt tool. One common problem is that a header file gets included multiple times within the same translation unit. To prevent this, a header file can use an #ifndef as a guard:

    // AcmeGeo.h:#ifndef __ACME_GEO_H__#define __ACME_GEO_H__

    namespace AcmeGeo { class map {...} class legend {...}; class road {...}; class city {...};}

    #endif //__ACME_GEO_H__

  • In C, the preprocessor was often used to imitate const variables and inline functions:

    #define PI 3.141592654#define square(x) ((x) * (x))

    However, preprocessor macros used in this way were rather dangerous. One common mistake was to say:

    #define square(x) (x * x)

    Then square(1 + 2) evaluates as:

    square(1 + 2) => 1 + 2 * 1 + 2 = 1 + 2 + 2 = 5C++ inline functions and const variables are safer:

    const double PI = 3.141592654inline double square(double x) {return x * x;}

  • The compiler

    The preprocessor generates a translation unit containing pure C++ code (with no preprocessor directives).The compilers job is to turn this translation unit into an object file containing machine code.compile

  • An object file is language independent. On many systems, the format of an object file dates back to the days when programming was done largely in C.Roughly, an object file contains raw data (mostly consisting of machine code), and a symbol table whose entries point into the raw data.

    (A real object file contains much more information, such as import and export specifications, relocation specifications and debugging data.)

  • Each symbol in the symbol table corresponds to a function or global variable defined in the C/C++ source code.In C, the name of a symbol was often just the name of the function or variable. For instance, the symbol _main represents the function main(), and points to main()s machine code.

    However, this is not sufficient for C++, because the same function name can be overloaded with many different argument types:

    double square(double x);int square(int x);float square(float x);

    We need a different symbolname for each square [email protected]@[email protected][email protected]@[email protected]@@[email protected]

  • To handle overloading, C++ compilers encode a functions types into the symbol name for the function. For instance,

    void processInput(AcmeGeo::map m, int arg);void printResults(int format, bool verbose);

    are encoded (under Visual Studio) as:

    [email protected]@[email protected]@@[email protected][email protected]@[email protected]

    This technique is known asname mangling.

  • Name mangling can cause difficulties when interfacing to programs written other languages, such as C, that know nothing about name mangling.Suppose that a function foo was written in C, and we would like to access it from C++. Name mangling can be disabled for this function by declaring it to be extern C:

    extern C { void foo();}

    Now the C++ compiler will refer to foo using an unmangled symbol, which will match the symbol used for foo by the C compiler.

  • The Linker

    The linker combines multiple object files into a single executable program.Object files may refer to symbols defined by other object files, and the linkers main job is to connect these references to the correct locations in the other object files.


  • The linker allows us to combine several files into a single executable. Although an entire software project can be kept in a single file, it is useful to break up large pieces of software into many files:

    The structure of a large project is clearer if it is divided into a number of files.In a project developed by multiple people, different people can work on different files at the same time.Different files can be compiled separately, so that you dont have to recompile the entire project every time you make a small change.You can use libraries from other vendors without having to paste their source code into your source code (in fact, they may not even want to give their source code to you).

  • Declarations and Definitions

    A declaration describes the nature of a particular entity, but does not define it in detail. Examples of declarations:

    class Matrix; // declare (but dont define) a classvoid foo(int i); // declare (but dont defin

Search related