ComfyS
ComfyS

Reputation: 141

Declare function in static library, define it in application that uses that same library

I would like to declare a function called foo() inside of a static library and call it from within the static library. However, I would like to force the user of the application to provide the definition of foo(). Is something like this possible in C/C++?

So as an example imagine this to be the static library:

In foo.h:

void foo();

In foo.cpp:

#include "foo.h"

int main() {
   foo();
   return 0;
}

Then in the application that uses this static library:

In app.cpp:

#include "foo.h"

void foo() {
    // Do something here...
}

I imagine this must be what e.g. the Win32 API does with their WinMain() function, which essentially replaces the usual main(). How does this work though? In the above example the static library would of course not compile, due to an undefined reference to foo().

Upvotes: 6

Views: 1560

Answers (4)

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

There's nothing technically wrong with leaving a function undefined in a library and expecting the application to provide it. This is actually done by at least one mainstream product called lex (your computer may have a free implementation called flex). This is not a good style though, and lex/flex continue to use it mostly for backwards compatibility.

It is recommended to pass user functions to library code as callbacks at run time, rather than bind them at link time.

Incidentally, the lex library also contains a definition of main, so this, too, is not unheard of.

Upvotes: 1

Xirema
Xirema

Reputation: 20386

Generally speaking, this kind of functionality is usually achieved with function pointers.

//header.h
typedef int(*add_func)(int, int);

int perform_add(int a, int b, add_func func) {
    return func(a,b);
}

//In User .cpp file
#include<Header.h>

int my_add_func(int a, int b) {
    return a; //Ooooh, edgy!
}

int my_other_add_func(int a, int b) {
    return a + 2 * b; //Don't cut yourself with that edge!
}

int main() {
    int val = perform_add(1, 5, my_add_func);
    val = perform_add(val, val, my_other_add_func);
    return 0;
}

In C++, we usually use std::function to represent these pointers, since they're easier to read, and can also hold functors and lambdas.

//header.h
typedef std::function<int(int,int)> add_func;

int perform_add(int a, int b, add_func const& func) {
    return func(a,b);
}

//In User .cpp file
#include<Header.h>

int my_add_func(int a, int b) {
    return a; //Ooooh, edgy!
}

int my_other_add_func(int a, int b) {
    return a + 2 * b; //Don't cut yourself with that edge!
}

int main() {
    int val = perform_add(1, 5, my_add_func);
    val = perform_add(val, val, my_other_add_func);
    //The following would not have compiled if we just used function pointers.
    val = perform_add(val, 17, [val](int a, int b) {return a + b + val;});
    return 0;
}

Upvotes: 3

Ben Voigt
Ben Voigt

Reputation: 283614

Yes, it is possible. You already know how.

Your confusion lies in

the static library would of course not compile, due to an "undefined reference"

But "undefined reference" is not a compile error -- it is generated by the linker. And a static library is just an unlinked collection of compiled object files. (Plus maybe an index, so the linker can find which object files it needs efficiently without scanning each one)

When the linker does run, it will be provided with both the application objects and the library, and nothing will be left unresolved.

Dynamic libraries are created via a linking step; static libraries aren't.

Upvotes: 10

user0042
user0042

Reputation: 8018

However, I would like to force the user of the application to provide the definition of foo(). Is something like this possible in C/C++?

You're already doing that implicitly. The library you have has a reference to foo() as it was declared in the header.

If the application doesn't provide a definition for foo(), you'll end up with a linking error.
To fix that, a user of your library needs to provide a definition of foo().

Your static library can be compiled though, the linker error will occur only if you create an executable or shared library using it.

You should document that in the header file.

Upvotes: 3

Related Questions