Putting it together
- C++ course
- Expert
- Lesson 47/47
- 6 min
Combine all expert topics into a working mini app.
C-compatible interface with extern "C"
The C++ compiler applies name mangling to function names (for example, engine_report becomes _Z13engine_reportv). This is needed for overloading, but it makes calls from C or other languages harder. An extern "C" declaration disables mangling.
In this final lesson we combine every expert topic: Factorial<5>::value (TMP), Engine::parallelSum() (atomic), the fake register access (volatile) and an extern "C" interface (ABI). The result is a single report function callable from C as well.
Combining all pieces
In the final step we combine all pieces inside an extern "C" function. This function can be called from C as well, because no mangling is applied to its name. Inside it we use the compile-time factorial and the parallel sum together.
Example: extern "C" int engine_report() { return Factorial<5>::value + Engine::parallelSum(); }. This function returns 120 + 36 = 156. We call it from main with std::cout << engine_report();. This way all expert topics meet in a single ABI interface.
Practice Add the extern "C" engine_report function
Take the previous lesson's solution. After the Factorial template add extern "C" int engine_report() with body return Factorial<5>::value + Engine::parallelSum();. In main after the register output add std::cout << engine_report();.
Starter code
#include <iostream>
#include <atomic>
#include <thread>
#include <cstdint>
class Engine {
public:
static const int Version = 1;
static int parallelSum() {
std::atomic<int> total{0};
std::thread t1([&]() { for (int i = 1; i <= 4; ++i) total += i; });
std::thread t2([&]() { for (int i = 5; i <= 8; ++i) total += i; });
t1.join();
t2.join();
return total.load();
}
static std::uint32_t readRegister(volatile std::uint32_t* reg) {
return *reg;
}
static void writeRegister(volatile std::uint32_t* reg, std::uint32_t value) {
*reg = value;
}
};
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
// Add the C-compatible report function here
int main() {
std::cout << "Ready" << std::endl;
std::cout << Factorial<5>::value << std::endl;
std::cout << Engine::parallelSum() << std::endl;
volatile std::uint32_t reg = 0;
Engine::writeRegister(®, 64);
std::cout << Engine::readRegister(®) << std::endl;
// Add the engine_report call
return 0;
}Sample solution
#include <iostream>
#include <atomic>
#include <thread>
#include <cstdint>
class Engine {
public:
static const int Version = 1;
static int parallelSum() {
std::atomic<int> total{0};
std::thread t1([&]() { for (int i = 1; i <= 4; ++i) total += i; });
std::thread t2([&]() { for (int i = 5; i <= 8; ++i) total += i; });
t1.join();
t2.join();
return total.load();
}
static std::uint32_t readRegister(volatile std::uint32_t* reg) {
return *reg;
}
static void writeRegister(volatile std::uint32_t* reg, std::uint32_t value) {
*reg = value;
}
};
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
extern "C" int engine_report() {
return Factorial<5>::value + Engine::parallelSum();
}
int main() {
std::cout << "Ready" << std::endl;
std::cout << Factorial<5>::value << std::endl;
std::cout << Engine::parallelSum() << std::endl;
volatile std::uint32_t reg = 0;
Engine::writeRegister(®, 64);
std::cout << Engine::readRegister(®) << std::endl;
std::cout << engine_report();
return 0;
}Expected output
Ready 120 36 64 156
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What does extern "C" do?
extern "C" int engine_report();- It hides names
- It changes the operating system
- It disables name mangling Correct answer
- It increases runtime checks
Explanation: extern "C" prevents name mangling on the function name.
2 Match each piece to its role
| Term | Meaning |
|---|---|
extern "C" |
C-compatible interface |
Factorial<5>::value |
Compile-time constant |
std::atomic<int> |
Parallel safe counter |
volatile |
Hardware register access |
3 Complete the extern "C" declaration
extern "C" ____ engine_report() { return Factorial<5>::value + Engine::parallelSum(); }
extern "C" int engine_report() { return Factorial<5>::value + Engine::parallelSum(); }
Explanation: The return type is int; it returns a number.