SlideShare a Scribd company logo
1 of 27
Download to read offline
1
Nico Ludwig (@ersatzteilchen)
(9) C++ Abstractions
2
TOC
● (9) C++ Abstractions
– Compile Time and Link Time Dependencies with UDTs
– Modularization
– Using Types in Size and using Types in Name
– How to reduce Compile Time Dependencies
– Internal and external Linkage
– Name Mangling and Application Binary Interfaces (ABIs)
– Static and dynamic linked Libraries
● Sources:
– Bjarne Stroustrup, The C++ Programming Language
– John Lakos, Large Scale C++ Software Design
3
Regulation of Modularization is required
● The C/C++ family of programming languages doesn't regulate the module system.
– It's based on h-files (mind the standard library), but that's all we know!
● We have to define how we're going exploit h-files to get a useful module system:
– John Lakos defines a set of rules in his book "Large Scale C++ Software Design".
– He describes and proves how large modular software can be created in C++.
● Required knowledge to understand this lecture:
– Preprocessor
– #include guards
● Let's define our first rules:
– R1: Each type is defined in a dedicated h-file.
– R2: Each h-file is adorned with #include guards.
● We're discussing physical, not logical
dependencies now! Alas we have to discuss this,
because logical dependencies influence physical
dependencies, esp. in C++.
4
A naïve Module
● To understand C++-modularization we've to discuss compilation and linking.
– Let's analyze a naïvely implemented type Car in Car.h, obeying R1 and R2:
// Car.h
#ifndef CAR_H_INCLUDED
#define CAR_H_INCLUDED
#include "Engine.h"
#include "Tyre.h"
class Car {
Engine* theEngine;
Tyre spareTyre;
public:
void StartEngine() { theEngine->Start(); }
void SetSpareTyre(Tyre spareTyre) {
this->spareTyre = spareTyre;
}
Tyre GetSpareTyre() { return spareTyre; }
};
#endif
// Engine.h
#ifndef ENGINE_H_INCLUDED
#define ENGINE_H_INCLUDED
class Engine {
public:
void Start() {}
};
#endif
// Tyre.h
#ifndef TYRE_H_INCLUDED
#define TYRE_H_INCLUDED
class Tyre {
};
#endif
// Main.cpp
#include "Car.h"
Car car;
car.StartEngine();
5
Review of the Build Phases of that Module
● Let's put the h-files Engine.h and Car.h into the "build phases diagram":
– Compile time dependency: Car depends on Engine, Engine.h is needed to compile Car.cpp tu.
– Link time dependency: Car depends on Engine, Car.o uses undefined symbols (Engine::Start()) that get satisfied by Engine.o.
– A compile time dependency almost always implies a link time dependency!
// Car.cpp
#include "Car.h"
// Car.cpp tu
// Engine.cpp
#include "Engine.h"
Engine.o Car.o
// Engine.cpp tu
Main.exe (or a.out)
Preprocessor
C/C++ Compiler
C/C++ Linker
I need Engine::Start()!I provide Engine::Start()!
// Engine.h
// Main.cpp
#include "Car.h"
// Main.cpp tu
Main.o I need Car::StartEngine()!
// Car.h
#include "Engine.h"
6
Compilation: The Usage Perspective of UDTs
● Next, let's analyze, how the type Car is composed:
– There are two fields: an Engine* and a Tyre.
– There are three member functions:
● Car::SetSpareTyre() and Car::GetSpareTyre(), which accept and return Tyre objects and
●
Car::StartEngine(), which neither accepts nor returns objects.
● Then let's analyze how the UDT Car uses the types Engine and Tyre:
– Car has fields of type Engine* and Tyre.
– Engine's member function Start() is called.
– The cctor and copy-assignment of Tyre are used.
class Car { // (members hidden)
public:
void StartEngine() { theEngine->Start(); }
void SetSpareTyre(Tyre spareTyre) {
this->spareTyre = spareTyre;
}
Tyre GetSpareTyre() { return spareTyre; }
};
class Car { // (members hidden)
Engine* theEngine;
Tyre spareTyre;
/* pass */
};
7
Compilation: The Usage Perspective of h-Files – Using
Types in Size
● How does the compiler "see" types?
– We're discussing physical, not logical dependencies now!
– And we've to change the perspective: how does Car.h use the contributed types?
● Car.h "needs to see" the type definitions of Engine and Tyre in order
to compile.
– This is because members of these types are used in Car.h!
● In C++ this dependency is called "using in size":
Car.h uses Engine and Tyre in size.
● A code file that uses types in size has to #include the definitions of
these types directly or indirectly.
// Car.h (contents hidden)
#include "Engine.h"
#include "Tyre.h"
class Car {
Engine* theEngine;
Tyre spareTyre;
public:
void StartEngine() {
theEngine->Start();
}
void SetSpareTyre(Tyre spareTyre) {
this->spareTyre = spareTyre;
}
Tyre GetSpareTyre() {
return spareTyre;
}
};
● What does that mean "a type definition has to be
included directly or indirectly"?
8
Compilation: Compile Time Dependencies
● If an h-file needs to see types in size, including "their" h-files is needed after R1.
● There's a problem: if an included h-file changes, all includers need recompilation!
– This is also true, if the including files don't even make use of these changes!
● E.g. let's modify Engine in Engine.h by adding a new member function GetStatus():
– After this change, all includers need to recompile!
– 1. Also Car.h, although it was not even modified!
– 2. Also all includers of Car.h, incl. Main.cpp!
– => This is because Engine.h and Car.h have changed. (Of course the executable needs to be relinked!)
// Engine.h (contents hidden)
class Engine { // (members hidden)
public:
int GetStatus() { /* pass */ }
};
// Car.h (contents hidden)
#include "Engine.h"
class Car { // (members hidden)
Engine* theEngine;
public:
void StartEngine() {
theEngine->Start();
}
};
recompilation required
// Main.cpp (contents hidden)
#include "Car.h" recompilation required
● If only a comment was changed in an h-file, all
includers would have to recompile as well!
9
Resolving Compile Time Dependencies: Forward Declarations
● To "fix" the "use in size"-dependency we'll move the usage of a type into a c-file.
– 1. Moving the implementation of Car::StartEngine() into Car.cpp (non-inline):
– 2. In Car.h we no longer have to include Engine.h. We only forward declare Engine!
– 3. But then we have to include Engine.h into Car.cpp, where it is used in size now.
– => Car.h does now use Engine in name and Car.cpp uses Engine in size!
// Car.h (contents hidden)
#include "Engine.h"
class Car { // (members hidden)
Engine* theEngine;
public:
void StartEngine();
};
// Car.cpp (contents hidden)
#include "Car.h"
void Car::StartEngine() {
theEngine->Start();
}
// Car.h (contents hidden)
class Engine; // Forward declaration of Engine.
class Car { // (members hidden)
Engine* theEngine; // Engine used in name.
public:
void StartEngine();
};
// Car.cpp (contents hidden)
#include "Car.h"
#include "Engine.h"
void Car::StartEngine() {
theEngine->Start(); // Engine used in size.
}
10
Resolving Compile Time Dependencies: It works!
● If we modify Engine.h, only the includers of Engine.h need recompilation:
● Only Car.cpp needs recompilation!
– Car.cpp uses Engine in size and needs to "see" Engine's definition (In a modified tu!).
– Car.h uses Engine in name, it only has to "know", that there'll exist the type Engine.
– Of course the executable needs to be relinked!
// Engine.h (contents hidden)
class Engine {
public:
void Start() { /* pass */ }
int GetStatus() { /* pass */ }
};
// Car.h (contents hidden)
class Engine;
class Car { // (members hidden)
Engine* theEngine;
public:
void StartEngine();
};
(uses in Engine in name, Engine.h not included)
no recompilation required
// Car.cpp (contents hidden)
#include "Car.h"
#include "Engine.h"
void Car::StartEngine() {
theEngine->Start();
}
no recompilation required
(uses Engine in size)
recompilation required
// Main.cpp (contents hidden)
#include "Car.h"
11
What's behind "using Types in Size"?
● W/ this new tool (forward declaration), we'll change Car.h to use Tyre in name as well:
● Now we can better understand the term "use in size":
– In former versions of Car, the sizes of Engine and Tyre needed to be known to make this work:
– formerCarsSize will be composed of the sizes of all full-object-fields of Car!
– If Car is composed of pointer-fields, the fields' sizes are the same (e.g. 4 == sizeof(void*))!
// Car.h (contents hidden)
class Tyre;
class Car { // (members hidden)
Tyre* spareTyre; // As pointer!
public:
void SetSpareTyre(Tyre* spareTyre);
Tyre* GetSpareTyre();
};
// Car.cpp (contents hidden) Tyre.h won't be included!
#include "Car.h"
void Car::SetSpareTyre(Tyre* spareTyre) {
this->spareTyre = spareTyre; // Pointer assignment.
}
Tyre* Car::GetSpareTyre() {
return spareTyre; // Pointer cctor.
}
Tyre
(uses Tyre in name) (uses Tyre in name)
std::size_t formerCarsSize = sizeof(Car);
std::size_t formerCarsSize = sizeof(Engine*) + sizeof(Tyre);
std::size_t carsSize = 4 + /* = sizeof(Engine*) */ + 4 /* = sizeof(Tyre*) */; // 32b-system
12
Using Types in Size and in Name: Edge Cases
● Parameters and return types are never used in size.
– If we retain the non-pointer Tyre parameters, a forward declaration is sufficient:
– => Using types in parameters creates only a "using in name"-dependency.
– On the declaration of functions the compiler doesn't need to know the type sizes!
– The same is valid for return-types.
● STL types (e.g. std::string) are not allowed to be forward declared!
– It's possible on many compilers, but it's not portable.
// Car.h (contents hidden)
class Tyre;
class Car { // (members hidden)
Tyre* spareTyre; // Not used in size!
public:
// Both functions use Tyre in name only!
void SetSpareTyre(Tyre spareTyre);
Tyre GetSpareTyre();
};
13
Summary
● Modularization is required to have reusable code, esp. UDTs.
– Modularization is achieved by reducing dependencies.
● Compile time dependencies are independent of UDT accessors in C++ (private etc.)!
● Types are used in name
– if they are used as pointer or reference types in fields of a UDT and
– if they are "mentioned" in function declarations (return and/or parameter).
– If types depend on each mutually using in name is required!
● Types are used in size
– if they are used as full-objects in fields or as base type of a UDT or
– if their interface is used in an implementation (in function code, esp. inline code).
● Mind and exploit the discussed edge cases (parameter and return types).
● References can be impractical as fields, as they
need to be initialized in ctors.
14
Finally let's complete our Rules for C++ Modularization
● Believe in these simple rules! Don't be too clever!
● R1: Each type is defined in a dedicated h-file.
● R2: Each h-file is adorned with #include guards.
● R3: Employ strict separated compilation.
– Use h-files and c-files and avoid inline member functions!
– A c-file includes "its" h-files as 1st
#include!
● R4: Strive to using types in name only.
– Avoid using full objects as fields; prefer pointers (and references (secondary)).
● R5: Only use UDTs, void*, char*, const char*, bool, int and double in interfaces!
– R5a: UDTs should be used as (const) references or (const) pointers preferably.
– Other types should only be used with a good reason! Here some more rules:
● R5b: Avoid using float, char, short or long! Don't blindly believe in what teachers tell you, these type are exotic in professional C++ programming!
●
R5c: Never use unsigned types!
15
Ok – But what have we archived?
● We learned that a compile time dependency is a dependency an itemA has to an h-file!
– Here, items in Main.cpp have compile time dependency to Car.h and transitively to Engine.h!
● When we use less types in size in h-files, less includes are required.
– After our changes we have this situation:
– Using types in name moved the compile time dependency from Main.cpp to Engine.h here!
– Using types in name is the way to reduce compile time dependencies and compilation time!
● The physical reusability of Car.h and the logical reusability ofCar has been enormously improved!
// Car.cpp
#include "Car.h"
// Engine.cpp
#include "Engine.h"
// Engine.h
// Main.cpp
#include "Car.h"
// Car.h
#include "Engine.h"
// Car.cpp
#include "Car.h"
#include "Engine.h"
// Engine.cpp
#include "Engine.h"
// Engine.h
// Main.cpp
#include "Car.h"
// Car.h
16
Reducing Dependencies means reducing Costs!
● Esp. in large C++ projects, compile time dependencies should be minimized!
– Changes in h-files have a bigger impact to compilation than changes in c-files!
– The compile time costs can be reduced.
– The risk of compile time errors can also be reduced.
● Reduced dependencies leads to improved reusability, it makes modules/UDTs versatile, valuable and user-friendly.
– The documentation of such modules/UDTs is usually "a piece of cake"!
● The difficulty to find errors in a C/C++ program increases in each build phase:
– Phase 1: preprocessing, phase 2: compile time and phase 3: link time.
– After each phase we've a greater "logical distance" to the original source code.
– (During run time the distance to the original source code reaches its maximum.)
● With this perspective we can state that compile time errors are significantly easier to find that link time errors!
– After we discussed compile time dependencies, let's discuss link time dependencies. - Then we can better understand and fix link
time errors.
17
Linking: How does the Linker "link"?
● Symbols defined in a tu (e.g. Engine::Start()) can be used in other tus (e.g. Car.cpp's tu).
● After compilation: symbols defined in an o-file can be used in another o-file.
– The connection is finally done by the linker. Let's have another look:
● When we talk about symbols we should ask: How does the linker "link"?
– The linker knows nothing about code, it knows about external and exported symbols!
– But which symbols of a tu are finally exported by the resulting o-file?
● Now we are going to discuss and understand linkage.
// Car.cpp tu
Engine.o Car.o
// Engine.cpp tu
Main.exe (or a.out)
C/C++ Compiler
C/C++ Linker
I need Engine::Start()!I provide Engine::Start()!
// Main.cpp tu
Main.o I need Car::StartEngine()!
18
Linking: How are Symbols resolved during Link Time?
● Each o-file has a table of the symbols it exports:
● Additionally do o-files record, which external symbols they need:
● The linker's job is to satisfy external symbols with exported symbols:
● The linker only processes a list of o-files!
– It is not interested in the names of the files, it only tries to satisfy link time dependencies.
– Multiple or non-matching exported/external symbols result in a link time error.
Engine.o ;(excerpt)
exports Engine::Start()
Car.o ;(excerpt)
exports Car::StartEngine()
exports Car::GetSpareTyre()
Engine.o ;(excerpt)
exports Engine::Start()
Car.o ;(excerpt)
requires Engine::Start()
Car.o ;(excerpt)
requires Engine::Start()
satisfies link time dependency
BlahBlah.o ;(excerpt)
exports Engine::Start()
Car.o ;(excerpt)
requires Engine::Start()
also satisfies link time dependency
19
Linking: Finally – What's linkage?
● Linkage describes the visibility of symbols of an o-file to the linker.
● Important about symbols is that not all of them are being exported!
– There exist symbols that have external linkage.
– There exist symbols that have internal linkage.
– There exist symbols that have no linkage at all.
● E.g. free functions have external linkage:
// Main.cpp
void Foo(); // Somewhere Foo() will be defined.
Foo();
// Foo.cpp
void Foo() {}
Foo.o
Main.o I need Foo()!
C/C++ Linker
I provide Foo()!
satisfies link time dependency
Main.exe (or a.out)
20
Linking: Example of Linkage
● Global/free variables do also have external linkage:
– Notice the extern keyword to notate the variable declaration of globalVariable.
● Global/free constants have internal linkage:
// Main.cpp
extern int globalVariable; // Somewhere globalVariable
// will be defined.
globalVariable = 300;
// Foo.cpp
int globalVariable = 42;
Foo.o
Main.o I need globalVariable!
C/C++ Linker
I provide globalVariable!
satisfies link time dependency
// Main.cpp
extern const int globalConstant; // Somewhere else globalConstant will be defined.
std::cout<<globalConstant<<std::endl;
// Foo.cpp
const int globalConstant = 23;
Foo.o
Main.o I need globalConstant!
C/C++ Linker: Error
I provide nothing!
Main.exe (or a.out)
21
C++ Symbols with external, internal and no Linkage
● External linkage:
– Free functions.
– Free variables.
– Member functions (static and non-static).
– (The linker can remove unused symbols with external linkage to minify executables.)
● Internal linkage:
– Free constants (by default).
– static free functions (deprecated in C++).
– inline free and member functions.
– (Items in anonymous namespaces.)
● No linkage:
– UDTs
– Preprocessor symbols
22
Name Mangling
● In C++, functions can have overloads. How does it influence exported symbols?
– The solution is simple: all exported symbols need to be unique for the linker!
– The compiler automatically adorns exported symbols w/ prefixes and suffixes to make overloads of functions distinguishable for
the linker.
– This name adorning is called name mangling.
● E.g. gcc produces following mangled names for Foo() and its overload Foo(int):
● Name mangling results in the Application Binary Interface (ABI) of an o-file.
● The ABI is usually influenced by
– function's interfaces: name mangling, calling convention, exception declaration,
– UDT's interfaces: padding and the layout of virtual function tables and
– the platform (x86, x64, ARM etc.).
Foo.o ;(excerpt)
00000010 T __Z3Fooi
00000000 T __Z3Foov
// Foo.cpp
void Foo(int i) {}
void Foo() {}
Foo.o ;(excerpt)
00000000 T __Z3Foov
// Foo.cpp
void Foo() {}
● An o-file demanding a prototype that is different
from provided external symbol won't link. Name
mangling demands not only the name but also the
argument list to match exactly.
● This is different in C, where calling a function
from a different prototype is a disaster as the
partial sf would not have the layout expected by
the implementation.
● ARM: the architecture developed by ARM plc
(earlier known as "Advanced RISC Machines Ldt").
23
Name Mangling and Link Time Compatibility
● Problem: different compilers of different vendors create different ABIs!
– E.g. the name mangling of the Borland compiler is different from gcc's.
– The result: the Borland linker does not understand exports that were created by gcc.
– Linker error message: "unresolved symbol Foo()"
● C++ does not standardize name mangling and ABIs.
– Technologies like the Component Object Model (COM) try to get rid of differing ABIs by standardization. Also between different
ABIs of different programming languages!
// Main.cpp
void Foo(); // Somewhere Foo()
// will be defined.
Foo();
// Foo.cpp
void Foo() {}
Foo.o
Main.o I need __Foo_n_1!
Borland Linker for C++: Error
I provide __Z3Foov!
compiled with gcc
compiled with Borland C++
● COM: the calling conventions have been normalized
to __stdcall, declared exceptions as well as function
overloads are not allowed.
24
The C-Linkage Specification
● With a C-linkage specification name mangling can be disabled.
– In C, no name mangling is required, because functions can't be overloaded.
● The C standard requires functions' export symbols to have a _ as prefix...
– and that's all the ABI! - Symbols with that "format" are accepted by each linker!
// Main.cpp
#include "Foo.h"
Foo();
// Foo.cpp
#include "Foo.h"
void Foo() {}
Foo.o
Main.o I need _Foo!
Borland Linker for C++: Ok
I provide _Foo!
compiled with gcc
compiled with Borland C++
// Foo.h
extern "C" { // All function declarations in this block have C-linkage.
void Foo();
}
Main.exe (or a.out)
Foo.o ;(excerpt)
00000000 T _Foo
● So, the ABI of C's o-files is predictable!
● Maybe it is required to add a specific calling
convention that was "agreed upon" between the
provider and consumer of the o-files.
25
Static and dynamic linked Libraries
● Usually o-files are linked together to library files (libraries).
– These libraries are then linked with our o-files to get the resulting executable.
● Static (linked) libraries: Libraries can be linked to the executable atlink time.
– Typically these are .lib-files or .a-files.
– The usage of static libraries enlarges the size of the resulting executable file!
● Because the libraries are completely linked into the executable file.
● Dynamic (linked) libraries: Libraries can be linked to the executable atrun time.
– Dynamic libraries are sometimes called "shared libraries".
– Typically these are .dll-files, .so-files or .dylib-files
– On link time a stub file is needed to satisfy symbols that get loaded during run time.
– Using dynamic libraries minimizes the size of resulting executable file!
●
Because the libraries are not completely linked into the executable file.
– But the executable can only run, if the dynamic libraries can be found during run time.
26
Static and dynamic linked Libraries in Action
● Using the static linked library "utilities.a":
● Using the dynamic linked library "utilities.dylib":
C/C++ Linker
utilities.aMain.o I need Foo()! I do provide Foo()!
a.out
C/C++ Linker
utilities.dylibMain.o I need Foo()! I will provide Foo()!
a.out
utilities.dylib I do provide Foo()!
Run Time
27
Thank you!

More Related Content

Viewers also liked

Asturias anegada
Asturias anegadaAsturias anegada
Asturias anegadaFernando
 
Crestwood Park Planned Unit Development
Crestwood Park Planned Unit DevelopmentCrestwood Park Planned Unit Development
Crestwood Park Planned Unit Developmentjasonsullivanwa
 
2013 Homeless Coalition Training Re-count
2013 Homeless Coalition Training Re-count2013 Homeless Coalition Training Re-count
2013 Homeless Coalition Training Re-counthomelessofhc
 
Peligros de utilizar las nuevas tecnologías
Peligros de utilizar las nuevas tecnologíasPeligros de utilizar las nuevas tecnologías
Peligros de utilizar las nuevas tecnologíaslucasyfede
 
以成本角度選擇網頁應用程式防禦策略
以成本角度選擇網頁應用程式防禦策略以成本角度選擇網頁應用程式防禦策略
以成本角度選擇網頁應用程式防禦策略Fan-Yu Kuan
 
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...VolunteerMatch
 
My future
My futureMy future
My futureronka62
 
4k Protest in Sao Paulo
4k Protest in Sao Paulo 4k Protest in Sao Paulo
4k Protest in Sao Paulo Naty Nats
 
Introducció Una Nova Cultura PolíTica
Introducció Una Nova Cultura PolíTicaIntroducció Una Nova Cultura PolíTica
Introducció Una Nova Cultura PolíTicajordijoly
 
Anatomy artifact p1
Anatomy artifact p1Anatomy artifact p1
Anatomy artifact p1777notw777
 
City Council 01.02.14 Agenda Item 6.2
City Council 01.02.14 Agenda Item 6.2City Council 01.02.14 Agenda Item 6.2
City Council 01.02.14 Agenda Item 6.2epdevelopment
 

Viewers also liked (14)

Asturias anegada
Asturias anegadaAsturias anegada
Asturias anegada
 
Crestwood Park Planned Unit Development
Crestwood Park Planned Unit DevelopmentCrestwood Park Planned Unit Development
Crestwood Park Planned Unit Development
 
2013 Homeless Coalition Training Re-count
2013 Homeless Coalition Training Re-count2013 Homeless Coalition Training Re-count
2013 Homeless Coalition Training Re-count
 
E124 Tma 03 Part 6
E124 Tma 03 Part 6E124 Tma 03 Part 6
E124 Tma 03 Part 6
 
Chiinaeninfo
ChiinaeninfoChiinaeninfo
Chiinaeninfo
 
Peligros de utilizar las nuevas tecnologías
Peligros de utilizar las nuevas tecnologíasPeligros de utilizar las nuevas tecnologías
Peligros de utilizar las nuevas tecnologías
 
以成本角度選擇網頁應用程式防禦策略
以成本角度選擇網頁應用程式防禦策略以成本角度選擇網頁應用程式防禦策略
以成本角度選擇網頁應用程式防禦策略
 
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...
Relative Impact ROI Part 2 – Getting the most bang-for the-buck out of the mo...
 
My future
My futureMy future
My future
 
Music icons final
Music icons finalMusic icons final
Music icons final
 
4k Protest in Sao Paulo
4k Protest in Sao Paulo 4k Protest in Sao Paulo
4k Protest in Sao Paulo
 
Introducció Una Nova Cultura PolíTica
Introducció Una Nova Cultura PolíTicaIntroducció Una Nova Cultura PolíTica
Introducció Una Nova Cultura PolíTica
 
Anatomy artifact p1
Anatomy artifact p1Anatomy artifact p1
Anatomy artifact p1
 
City Council 01.02.14 Agenda Item 6.2
City Council 01.02.14 Agenda Item 6.2City Council 01.02.14 Agenda Item 6.2
City Council 01.02.14 Agenda Item 6.2
 

Similar to (9) cpp abstractions separated_compilation_and_binding_part_ii

Session 4 - Object oriented programming with Objective-C (part 2)
Session 4  - Object oriented programming with Objective-C (part 2)Session 4  - Object oriented programming with Objective-C (part 2)
Session 4 - Object oriented programming with Objective-C (part 2)Vu Tran Lam
 
(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_ii(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_iiNico Ludwig
 
(7) cpp abstractions inheritance_part_ii
(7) cpp abstractions inheritance_part_ii(7) cpp abstractions inheritance_part_ii
(7) cpp abstractions inheritance_part_iiNico Ludwig
 
C#i need help creating the instance of stream reader to read from .pdf
C#i need help creating the instance of stream reader to read from .pdfC#i need help creating the instance of stream reader to read from .pdf
C#i need help creating the instance of stream reader to read from .pdfajantha11
 
Software Engineer Screening Question - OOP
Software Engineer Screening Question - OOPSoftware Engineer Screening Question - OOP
Software Engineer Screening Question - OOPjason_scorebig
 
C language introduction geeksfor geeks
C language introduction   geeksfor geeksC language introduction   geeksfor geeks
C language introduction geeksfor geeksAashutoshChhedavi
 
Sahana introduction to the code v2
Sahana   introduction to the code v2Sahana   introduction to the code v2
Sahana introduction to the code v2AidIQ
 
(4) c sharp introduction_object_orientation_part_i
(4) c sharp introduction_object_orientation_part_i(4) c sharp introduction_object_orientation_part_i
(4) c sharp introduction_object_orientation_part_iNico Ludwig
 
Introduction to cpp language and all the required information relating to it
Introduction to cpp language and all the required information relating to itIntroduction to cpp language and all the required information relating to it
Introduction to cpp language and all the required information relating to itPushkarNiroula1
 
Object Oriented Programming
Object Oriented ProgrammingObject Oriented Programming
Object Oriented ProgrammingZain Abid
 

Similar to (9) cpp abstractions separated_compilation_and_binding_part_ii (20)

Session 4 - Object oriented programming with Objective-C (part 2)
Session 4  - Object oriented programming with Objective-C (part 2)Session 4  - Object oriented programming with Objective-C (part 2)
Session 4 - Object oriented programming with Objective-C (part 2)
 
(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_ii(5) c sharp introduction_object_orientation_part_ii
(5) c sharp introduction_object_orientation_part_ii
 
(7) cpp abstractions inheritance_part_ii
(7) cpp abstractions inheritance_part_ii(7) cpp abstractions inheritance_part_ii
(7) cpp abstractions inheritance_part_ii
 
Routing
RoutingRouting
Routing
 
C basics
C basicsC basics
C basics
 
C#i need help creating the instance of stream reader to read from .pdf
C#i need help creating the instance of stream reader to read from .pdfC#i need help creating the instance of stream reader to read from .pdf
C#i need help creating the instance of stream reader to read from .pdf
 
Software Engineer Screening Question - OOP
Software Engineer Screening Question - OOPSoftware Engineer Screening Question - OOP
Software Engineer Screening Question - OOP
 
Prog1-L1.pdf
Prog1-L1.pdfProg1-L1.pdf
Prog1-L1.pdf
 
C programming session9 -
C programming  session9 -C programming  session9 -
C programming session9 -
 
C language introduction geeksfor geeks
C language introduction   geeksfor geeksC language introduction   geeksfor geeks
C language introduction geeksfor geeks
 
Sahana introduction to the code v2
Sahana   introduction to the code v2Sahana   introduction to the code v2
Sahana introduction to the code v2
 
Sst hackathon express
Sst hackathon expressSst hackathon express
Sst hackathon express
 
C tutorials
C tutorialsC tutorials
C tutorials
 
C programming session10
C programming  session10C programming  session10
C programming session10
 
(4) c sharp introduction_object_orientation_part_i
(4) c sharp introduction_object_orientation_part_i(4) c sharp introduction_object_orientation_part_i
(4) c sharp introduction_object_orientation_part_i
 
Introduction to cpp language and all the required information relating to it
Introduction to cpp language and all the required information relating to itIntroduction to cpp language and all the required information relating to it
Introduction to cpp language and all the required information relating to it
 
Embedded C programming session10
Embedded C programming  session10Embedded C programming  session10
Embedded C programming session10
 
Object Oriented Programming
Object Oriented ProgrammingObject Oriented Programming
Object Oriented Programming
 
Open mp
Open mpOpen mp
Open mp
 
Basic c
Basic cBasic c
Basic c
 

More from Nico Ludwig

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_vNico Ludwig
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivNico Ludwig
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiNico Ludwig
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiNico Ludwig
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_iNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivityNico Ludwig
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_viNico Ludwig
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_vNico Ludwig
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_ivNico Ludwig
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iiiNico Ludwig
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_iiNico Ludwig
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_iNico Ludwig
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNico Ludwig
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNico Ludwig
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNico Ludwig
 

More from Nico Ludwig (20)

Grundkurs fuer excel_part_v
Grundkurs fuer excel_part_vGrundkurs fuer excel_part_v
Grundkurs fuer excel_part_v
 
Grundkurs fuer excel_part_iv
Grundkurs fuer excel_part_ivGrundkurs fuer excel_part_iv
Grundkurs fuer excel_part_iv
 
Grundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iiiGrundkurs fuer excel_part_iii
Grundkurs fuer excel_part_iii
 
Grundkurs fuer excel_part_ii
Grundkurs fuer excel_part_iiGrundkurs fuer excel_part_ii
Grundkurs fuer excel_part_ii
 
Grundkurs fuer excel_part_i
Grundkurs fuer excel_part_iGrundkurs fuer excel_part_i
Grundkurs fuer excel_part_i
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(2) gui drawing
(2) gui drawing(2) gui drawing
(2) gui drawing
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
(1) gui history_of_interactivity
(1) gui history_of_interactivity(1) gui history_of_interactivity
(1) gui history_of_interactivity
 
New c sharp4_features_part_vi
New c sharp4_features_part_viNew c sharp4_features_part_vi
New c sharp4_features_part_vi
 
New c sharp4_features_part_v
New c sharp4_features_part_vNew c sharp4_features_part_v
New c sharp4_features_part_v
 
New c sharp4_features_part_iv
New c sharp4_features_part_ivNew c sharp4_features_part_iv
New c sharp4_features_part_iv
 
New c sharp4_features_part_iii
New c sharp4_features_part_iiiNew c sharp4_features_part_iii
New c sharp4_features_part_iii
 
New c sharp4_features_part_ii
New c sharp4_features_part_iiNew c sharp4_features_part_ii
New c sharp4_features_part_ii
 
New c sharp4_features_part_i
New c sharp4_features_part_iNew c sharp4_features_part_i
New c sharp4_features_part_i
 
New c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_vNew c sharp3_features_(linq)_part_v
New c sharp3_features_(linq)_part_v
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_ivNew c sharp3_features_(linq)_part_iv
New c sharp3_features_(linq)_part_iv
 
New c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iiiNew c sharp3_features_(linq)_part_iii
New c sharp3_features_(linq)_part_iii
 
New c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_iiNew c sharp3_features_(linq)_part_ii
New c sharp3_features_(linq)_part_ii
 

(9) cpp abstractions separated_compilation_and_binding_part_ii

  • 2. 2 TOC ● (9) C++ Abstractions – Compile Time and Link Time Dependencies with UDTs – Modularization – Using Types in Size and using Types in Name – How to reduce Compile Time Dependencies – Internal and external Linkage – Name Mangling and Application Binary Interfaces (ABIs) – Static and dynamic linked Libraries ● Sources: – Bjarne Stroustrup, The C++ Programming Language – John Lakos, Large Scale C++ Software Design
  • 3. 3 Regulation of Modularization is required ● The C/C++ family of programming languages doesn't regulate the module system. – It's based on h-files (mind the standard library), but that's all we know! ● We have to define how we're going exploit h-files to get a useful module system: – John Lakos defines a set of rules in his book "Large Scale C++ Software Design". – He describes and proves how large modular software can be created in C++. ● Required knowledge to understand this lecture: – Preprocessor – #include guards ● Let's define our first rules: – R1: Each type is defined in a dedicated h-file. – R2: Each h-file is adorned with #include guards. ● We're discussing physical, not logical dependencies now! Alas we have to discuss this, because logical dependencies influence physical dependencies, esp. in C++.
  • 4. 4 A naïve Module ● To understand C++-modularization we've to discuss compilation and linking. – Let's analyze a naïvely implemented type Car in Car.h, obeying R1 and R2: // Car.h #ifndef CAR_H_INCLUDED #define CAR_H_INCLUDED #include "Engine.h" #include "Tyre.h" class Car { Engine* theEngine; Tyre spareTyre; public: void StartEngine() { theEngine->Start(); } void SetSpareTyre(Tyre spareTyre) { this->spareTyre = spareTyre; } Tyre GetSpareTyre() { return spareTyre; } }; #endif // Engine.h #ifndef ENGINE_H_INCLUDED #define ENGINE_H_INCLUDED class Engine { public: void Start() {} }; #endif // Tyre.h #ifndef TYRE_H_INCLUDED #define TYRE_H_INCLUDED class Tyre { }; #endif // Main.cpp #include "Car.h" Car car; car.StartEngine();
  • 5. 5 Review of the Build Phases of that Module ● Let's put the h-files Engine.h and Car.h into the "build phases diagram": – Compile time dependency: Car depends on Engine, Engine.h is needed to compile Car.cpp tu. – Link time dependency: Car depends on Engine, Car.o uses undefined symbols (Engine::Start()) that get satisfied by Engine.o. – A compile time dependency almost always implies a link time dependency! // Car.cpp #include "Car.h" // Car.cpp tu // Engine.cpp #include "Engine.h" Engine.o Car.o // Engine.cpp tu Main.exe (or a.out) Preprocessor C/C++ Compiler C/C++ Linker I need Engine::Start()!I provide Engine::Start()! // Engine.h // Main.cpp #include "Car.h" // Main.cpp tu Main.o I need Car::StartEngine()! // Car.h #include "Engine.h"
  • 6. 6 Compilation: The Usage Perspective of UDTs ● Next, let's analyze, how the type Car is composed: – There are two fields: an Engine* and a Tyre. – There are three member functions: ● Car::SetSpareTyre() and Car::GetSpareTyre(), which accept and return Tyre objects and ● Car::StartEngine(), which neither accepts nor returns objects. ● Then let's analyze how the UDT Car uses the types Engine and Tyre: – Car has fields of type Engine* and Tyre. – Engine's member function Start() is called. – The cctor and copy-assignment of Tyre are used. class Car { // (members hidden) public: void StartEngine() { theEngine->Start(); } void SetSpareTyre(Tyre spareTyre) { this->spareTyre = spareTyre; } Tyre GetSpareTyre() { return spareTyre; } }; class Car { // (members hidden) Engine* theEngine; Tyre spareTyre; /* pass */ };
  • 7. 7 Compilation: The Usage Perspective of h-Files – Using Types in Size ● How does the compiler "see" types? – We're discussing physical, not logical dependencies now! – And we've to change the perspective: how does Car.h use the contributed types? ● Car.h "needs to see" the type definitions of Engine and Tyre in order to compile. – This is because members of these types are used in Car.h! ● In C++ this dependency is called "using in size": Car.h uses Engine and Tyre in size. ● A code file that uses types in size has to #include the definitions of these types directly or indirectly. // Car.h (contents hidden) #include "Engine.h" #include "Tyre.h" class Car { Engine* theEngine; Tyre spareTyre; public: void StartEngine() { theEngine->Start(); } void SetSpareTyre(Tyre spareTyre) { this->spareTyre = spareTyre; } Tyre GetSpareTyre() { return spareTyre; } }; ● What does that mean "a type definition has to be included directly or indirectly"?
  • 8. 8 Compilation: Compile Time Dependencies ● If an h-file needs to see types in size, including "their" h-files is needed after R1. ● There's a problem: if an included h-file changes, all includers need recompilation! – This is also true, if the including files don't even make use of these changes! ● E.g. let's modify Engine in Engine.h by adding a new member function GetStatus(): – After this change, all includers need to recompile! – 1. Also Car.h, although it was not even modified! – 2. Also all includers of Car.h, incl. Main.cpp! – => This is because Engine.h and Car.h have changed. (Of course the executable needs to be relinked!) // Engine.h (contents hidden) class Engine { // (members hidden) public: int GetStatus() { /* pass */ } }; // Car.h (contents hidden) #include "Engine.h" class Car { // (members hidden) Engine* theEngine; public: void StartEngine() { theEngine->Start(); } }; recompilation required // Main.cpp (contents hidden) #include "Car.h" recompilation required ● If only a comment was changed in an h-file, all includers would have to recompile as well!
  • 9. 9 Resolving Compile Time Dependencies: Forward Declarations ● To "fix" the "use in size"-dependency we'll move the usage of a type into a c-file. – 1. Moving the implementation of Car::StartEngine() into Car.cpp (non-inline): – 2. In Car.h we no longer have to include Engine.h. We only forward declare Engine! – 3. But then we have to include Engine.h into Car.cpp, where it is used in size now. – => Car.h does now use Engine in name and Car.cpp uses Engine in size! // Car.h (contents hidden) #include "Engine.h" class Car { // (members hidden) Engine* theEngine; public: void StartEngine(); }; // Car.cpp (contents hidden) #include "Car.h" void Car::StartEngine() { theEngine->Start(); } // Car.h (contents hidden) class Engine; // Forward declaration of Engine. class Car { // (members hidden) Engine* theEngine; // Engine used in name. public: void StartEngine(); }; // Car.cpp (contents hidden) #include "Car.h" #include "Engine.h" void Car::StartEngine() { theEngine->Start(); // Engine used in size. }
  • 10. 10 Resolving Compile Time Dependencies: It works! ● If we modify Engine.h, only the includers of Engine.h need recompilation: ● Only Car.cpp needs recompilation! – Car.cpp uses Engine in size and needs to "see" Engine's definition (In a modified tu!). – Car.h uses Engine in name, it only has to "know", that there'll exist the type Engine. – Of course the executable needs to be relinked! // Engine.h (contents hidden) class Engine { public: void Start() { /* pass */ } int GetStatus() { /* pass */ } }; // Car.h (contents hidden) class Engine; class Car { // (members hidden) Engine* theEngine; public: void StartEngine(); }; (uses in Engine in name, Engine.h not included) no recompilation required // Car.cpp (contents hidden) #include "Car.h" #include "Engine.h" void Car::StartEngine() { theEngine->Start(); } no recompilation required (uses Engine in size) recompilation required // Main.cpp (contents hidden) #include "Car.h"
  • 11. 11 What's behind "using Types in Size"? ● W/ this new tool (forward declaration), we'll change Car.h to use Tyre in name as well: ● Now we can better understand the term "use in size": – In former versions of Car, the sizes of Engine and Tyre needed to be known to make this work: – formerCarsSize will be composed of the sizes of all full-object-fields of Car! – If Car is composed of pointer-fields, the fields' sizes are the same (e.g. 4 == sizeof(void*))! // Car.h (contents hidden) class Tyre; class Car { // (members hidden) Tyre* spareTyre; // As pointer! public: void SetSpareTyre(Tyre* spareTyre); Tyre* GetSpareTyre(); }; // Car.cpp (contents hidden) Tyre.h won't be included! #include "Car.h" void Car::SetSpareTyre(Tyre* spareTyre) { this->spareTyre = spareTyre; // Pointer assignment. } Tyre* Car::GetSpareTyre() { return spareTyre; // Pointer cctor. } Tyre (uses Tyre in name) (uses Tyre in name) std::size_t formerCarsSize = sizeof(Car); std::size_t formerCarsSize = sizeof(Engine*) + sizeof(Tyre); std::size_t carsSize = 4 + /* = sizeof(Engine*) */ + 4 /* = sizeof(Tyre*) */; // 32b-system
  • 12. 12 Using Types in Size and in Name: Edge Cases ● Parameters and return types are never used in size. – If we retain the non-pointer Tyre parameters, a forward declaration is sufficient: – => Using types in parameters creates only a "using in name"-dependency. – On the declaration of functions the compiler doesn't need to know the type sizes! – The same is valid for return-types. ● STL types (e.g. std::string) are not allowed to be forward declared! – It's possible on many compilers, but it's not portable. // Car.h (contents hidden) class Tyre; class Car { // (members hidden) Tyre* spareTyre; // Not used in size! public: // Both functions use Tyre in name only! void SetSpareTyre(Tyre spareTyre); Tyre GetSpareTyre(); };
  • 13. 13 Summary ● Modularization is required to have reusable code, esp. UDTs. – Modularization is achieved by reducing dependencies. ● Compile time dependencies are independent of UDT accessors in C++ (private etc.)! ● Types are used in name – if they are used as pointer or reference types in fields of a UDT and – if they are "mentioned" in function declarations (return and/or parameter). – If types depend on each mutually using in name is required! ● Types are used in size – if they are used as full-objects in fields or as base type of a UDT or – if their interface is used in an implementation (in function code, esp. inline code). ● Mind and exploit the discussed edge cases (parameter and return types). ● References can be impractical as fields, as they need to be initialized in ctors.
  • 14. 14 Finally let's complete our Rules for C++ Modularization ● Believe in these simple rules! Don't be too clever! ● R1: Each type is defined in a dedicated h-file. ● R2: Each h-file is adorned with #include guards. ● R3: Employ strict separated compilation. – Use h-files and c-files and avoid inline member functions! – A c-file includes "its" h-files as 1st #include! ● R4: Strive to using types in name only. – Avoid using full objects as fields; prefer pointers (and references (secondary)). ● R5: Only use UDTs, void*, char*, const char*, bool, int and double in interfaces! – R5a: UDTs should be used as (const) references or (const) pointers preferably. – Other types should only be used with a good reason! Here some more rules: ● R5b: Avoid using float, char, short or long! Don't blindly believe in what teachers tell you, these type are exotic in professional C++ programming! ● R5c: Never use unsigned types!
  • 15. 15 Ok – But what have we archived? ● We learned that a compile time dependency is a dependency an itemA has to an h-file! – Here, items in Main.cpp have compile time dependency to Car.h and transitively to Engine.h! ● When we use less types in size in h-files, less includes are required. – After our changes we have this situation: – Using types in name moved the compile time dependency from Main.cpp to Engine.h here! – Using types in name is the way to reduce compile time dependencies and compilation time! ● The physical reusability of Car.h and the logical reusability ofCar has been enormously improved! // Car.cpp #include "Car.h" // Engine.cpp #include "Engine.h" // Engine.h // Main.cpp #include "Car.h" // Car.h #include "Engine.h" // Car.cpp #include "Car.h" #include "Engine.h" // Engine.cpp #include "Engine.h" // Engine.h // Main.cpp #include "Car.h" // Car.h
  • 16. 16 Reducing Dependencies means reducing Costs! ● Esp. in large C++ projects, compile time dependencies should be minimized! – Changes in h-files have a bigger impact to compilation than changes in c-files! – The compile time costs can be reduced. – The risk of compile time errors can also be reduced. ● Reduced dependencies leads to improved reusability, it makes modules/UDTs versatile, valuable and user-friendly. – The documentation of such modules/UDTs is usually "a piece of cake"! ● The difficulty to find errors in a C/C++ program increases in each build phase: – Phase 1: preprocessing, phase 2: compile time and phase 3: link time. – After each phase we've a greater "logical distance" to the original source code. – (During run time the distance to the original source code reaches its maximum.) ● With this perspective we can state that compile time errors are significantly easier to find that link time errors! – After we discussed compile time dependencies, let's discuss link time dependencies. - Then we can better understand and fix link time errors.
  • 17. 17 Linking: How does the Linker "link"? ● Symbols defined in a tu (e.g. Engine::Start()) can be used in other tus (e.g. Car.cpp's tu). ● After compilation: symbols defined in an o-file can be used in another o-file. – The connection is finally done by the linker. Let's have another look: ● When we talk about symbols we should ask: How does the linker "link"? – The linker knows nothing about code, it knows about external and exported symbols! – But which symbols of a tu are finally exported by the resulting o-file? ● Now we are going to discuss and understand linkage. // Car.cpp tu Engine.o Car.o // Engine.cpp tu Main.exe (or a.out) C/C++ Compiler C/C++ Linker I need Engine::Start()!I provide Engine::Start()! // Main.cpp tu Main.o I need Car::StartEngine()!
  • 18. 18 Linking: How are Symbols resolved during Link Time? ● Each o-file has a table of the symbols it exports: ● Additionally do o-files record, which external symbols they need: ● The linker's job is to satisfy external symbols with exported symbols: ● The linker only processes a list of o-files! – It is not interested in the names of the files, it only tries to satisfy link time dependencies. – Multiple or non-matching exported/external symbols result in a link time error. Engine.o ;(excerpt) exports Engine::Start() Car.o ;(excerpt) exports Car::StartEngine() exports Car::GetSpareTyre() Engine.o ;(excerpt) exports Engine::Start() Car.o ;(excerpt) requires Engine::Start() Car.o ;(excerpt) requires Engine::Start() satisfies link time dependency BlahBlah.o ;(excerpt) exports Engine::Start() Car.o ;(excerpt) requires Engine::Start() also satisfies link time dependency
  • 19. 19 Linking: Finally – What's linkage? ● Linkage describes the visibility of symbols of an o-file to the linker. ● Important about symbols is that not all of them are being exported! – There exist symbols that have external linkage. – There exist symbols that have internal linkage. – There exist symbols that have no linkage at all. ● E.g. free functions have external linkage: // Main.cpp void Foo(); // Somewhere Foo() will be defined. Foo(); // Foo.cpp void Foo() {} Foo.o Main.o I need Foo()! C/C++ Linker I provide Foo()! satisfies link time dependency Main.exe (or a.out)
  • 20. 20 Linking: Example of Linkage ● Global/free variables do also have external linkage: – Notice the extern keyword to notate the variable declaration of globalVariable. ● Global/free constants have internal linkage: // Main.cpp extern int globalVariable; // Somewhere globalVariable // will be defined. globalVariable = 300; // Foo.cpp int globalVariable = 42; Foo.o Main.o I need globalVariable! C/C++ Linker I provide globalVariable! satisfies link time dependency // Main.cpp extern const int globalConstant; // Somewhere else globalConstant will be defined. std::cout<<globalConstant<<std::endl; // Foo.cpp const int globalConstant = 23; Foo.o Main.o I need globalConstant! C/C++ Linker: Error I provide nothing! Main.exe (or a.out)
  • 21. 21 C++ Symbols with external, internal and no Linkage ● External linkage: – Free functions. – Free variables. – Member functions (static and non-static). – (The linker can remove unused symbols with external linkage to minify executables.) ● Internal linkage: – Free constants (by default). – static free functions (deprecated in C++). – inline free and member functions. – (Items in anonymous namespaces.) ● No linkage: – UDTs – Preprocessor symbols
  • 22. 22 Name Mangling ● In C++, functions can have overloads. How does it influence exported symbols? – The solution is simple: all exported symbols need to be unique for the linker! – The compiler automatically adorns exported symbols w/ prefixes and suffixes to make overloads of functions distinguishable for the linker. – This name adorning is called name mangling. ● E.g. gcc produces following mangled names for Foo() and its overload Foo(int): ● Name mangling results in the Application Binary Interface (ABI) of an o-file. ● The ABI is usually influenced by – function's interfaces: name mangling, calling convention, exception declaration, – UDT's interfaces: padding and the layout of virtual function tables and – the platform (x86, x64, ARM etc.). Foo.o ;(excerpt) 00000010 T __Z3Fooi 00000000 T __Z3Foov // Foo.cpp void Foo(int i) {} void Foo() {} Foo.o ;(excerpt) 00000000 T __Z3Foov // Foo.cpp void Foo() {} ● An o-file demanding a prototype that is different from provided external symbol won't link. Name mangling demands not only the name but also the argument list to match exactly. ● This is different in C, where calling a function from a different prototype is a disaster as the partial sf would not have the layout expected by the implementation. ● ARM: the architecture developed by ARM plc (earlier known as "Advanced RISC Machines Ldt").
  • 23. 23 Name Mangling and Link Time Compatibility ● Problem: different compilers of different vendors create different ABIs! – E.g. the name mangling of the Borland compiler is different from gcc's. – The result: the Borland linker does not understand exports that were created by gcc. – Linker error message: "unresolved symbol Foo()" ● C++ does not standardize name mangling and ABIs. – Technologies like the Component Object Model (COM) try to get rid of differing ABIs by standardization. Also between different ABIs of different programming languages! // Main.cpp void Foo(); // Somewhere Foo() // will be defined. Foo(); // Foo.cpp void Foo() {} Foo.o Main.o I need __Foo_n_1! Borland Linker for C++: Error I provide __Z3Foov! compiled with gcc compiled with Borland C++ ● COM: the calling conventions have been normalized to __stdcall, declared exceptions as well as function overloads are not allowed.
  • 24. 24 The C-Linkage Specification ● With a C-linkage specification name mangling can be disabled. – In C, no name mangling is required, because functions can't be overloaded. ● The C standard requires functions' export symbols to have a _ as prefix... – and that's all the ABI! - Symbols with that "format" are accepted by each linker! // Main.cpp #include "Foo.h" Foo(); // Foo.cpp #include "Foo.h" void Foo() {} Foo.o Main.o I need _Foo! Borland Linker for C++: Ok I provide _Foo! compiled with gcc compiled with Borland C++ // Foo.h extern "C" { // All function declarations in this block have C-linkage. void Foo(); } Main.exe (or a.out) Foo.o ;(excerpt) 00000000 T _Foo ● So, the ABI of C's o-files is predictable! ● Maybe it is required to add a specific calling convention that was "agreed upon" between the provider and consumer of the o-files.
  • 25. 25 Static and dynamic linked Libraries ● Usually o-files are linked together to library files (libraries). – These libraries are then linked with our o-files to get the resulting executable. ● Static (linked) libraries: Libraries can be linked to the executable atlink time. – Typically these are .lib-files or .a-files. – The usage of static libraries enlarges the size of the resulting executable file! ● Because the libraries are completely linked into the executable file. ● Dynamic (linked) libraries: Libraries can be linked to the executable atrun time. – Dynamic libraries are sometimes called "shared libraries". – Typically these are .dll-files, .so-files or .dylib-files – On link time a stub file is needed to satisfy symbols that get loaded during run time. – Using dynamic libraries minimizes the size of resulting executable file! ● Because the libraries are not completely linked into the executable file. – But the executable can only run, if the dynamic libraries can be found during run time.
  • 26. 26 Static and dynamic linked Libraries in Action ● Using the static linked library "utilities.a": ● Using the dynamic linked library "utilities.dylib": C/C++ Linker utilities.aMain.o I need Foo()! I do provide Foo()! a.out C/C++ Linker utilities.dylibMain.o I need Foo()! I will provide Foo()! a.out utilities.dylib I do provide Foo()! Run Time