Skip to Content
Course content

144: Calling C Libraries from C++

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Why is the linker screaming at me even though the function is right there in the header?

I've seen this happen to almost every dev moving from pure C to C++. You include a C header, you call a function that clearly exists, and then the linker throws a "symbol not found" error. It feels like the linker is lying to you, but it's actually doing exactly what it was told.

The culprit is name mangling. In C, a function called calculate_checksum is just calculate_checksum in the binary. But C++ supports function overloading—having multiple functions with the same name but different arguments. To make that work, the C++ compiler "mangles" the name, turning calculate_checksum into something ugly like __Z16calculate_checksumi to encode the parameter types.

When you call a C function from C++, the C++ compiler looks for the mangled version. The C library, of course, only provides the unmangled version. They're speaking two different languages, and the linker can't bridge the gap on its own.

How do I actually tell C++ to stop mangling these names?

This is where extern "C" comes in. It's not a function or a variable; it's a linkage specification. It tells the C++ compiler: "Hey, for the following block of code, please use the C calling convention and don't mangle these names."

Imagine you have a simple C library for processing raw pixel data. Your C header image_proc.h looks like this:

// image_proc.h (Pure C)
void apply_grayscale(unsigned char* pixels, int width, int height);
int get_image_size(int width, int height);

If you try to use this in C++, you need to wrap the declaration. You can do it for a single function, but usually, you'll do it for the whole block:

// main.cpp
extern "C" {
    #include "image_proc.h"
}

int main() {
    unsigned char my_pixels[1024];
    apply_grayscale(my_pixels, 32, 32); // Now the linker knows to look for the C name
    return 0;
}

What if I don't want to wrap the include every single time?

Wrapping the include in main.cpp is fine for a quick hack, but it's a pain if you have twenty different files using that library. I'd rather fix the header once and forget about it. The problem is that extern "C" is a C++ keyword. If a pure C compiler sees it, it'll crash because it has no idea what that means.

The professional way to handle this is by using the __cplusplus macro. This macro is only defined when the compiler is in C++ mode. You can wrap your C header in a conditional check so it's compatible with both languages:

// image_proc.h (Now C++ compatible)
#ifndef IMAGE_PROC_H
#define IMAGE_PROC_H

#ifdef __cplusplus
extern "C" {
#endif

void apply_grayscale(unsigned char* pixels, int width, int height);
int get_image_size(int width, int height);

#ifdef __cplusplus
}
#endif

#endif

Now, whether you're compiling a .c file or a .cpp file, this header just works. If it's C++, the extern "C" block is active. If it's C, the preprocessor strips those lines out entirely. This is the industry standard for writing libraries that are meant to be portable.




📋 Practical Task

Fixing the Linker Errors in the "FastMath" C-Library Integration

You've been handed a legacy C library called fastmath.h and fastmath.c. The library provides a highly optimized function double fast_inv_sqrt(double n). Your task is to integrate this into a C++ project.

The Setup:

  • fastmath.h: Contains double fast_inv_sqrt(double n);
  • main.cpp: Includes fastmath.h and calls fast_inv_sqrt(25.0);

The Problem: When you compile the project, you get a linker error: undefined reference to 'fast_inv_sqrt(double)' (or a mangled version of it).

Your Task: Modify fastmath.h to use the __cplusplus macro and extern "C" so that it can be included in both C and C++ files without requiring the user to manually wrap the #include statement in their C++ code. Ensure the header remains valid for a standard C compiler.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.