basically i have a header full of function prototypes(util.h) and a cpp file with the functions body

// util.h
#include <ctime>

uint32_t GetTime( );
uint32_t GetTicks( );

// util.cpp
#include <util.h>

uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

uint32_t GetTicks( )
{
    return clock( );
}

// main.cpp
#include <conio.h>
#include <iostream>
#include "util.h"

int main(int argc, char* argv[])
{
    uint32_t StartTime = GetTicks( );
    // 
    // some code here
    //
    std :: cout << GetTicks( ) - StartTime << " milliseconds passed since the program started" << std :: endl;
    getch( );
    return 0;
}

because i'll use GetTicks( ) and GetTime( ) many times in my code and the function body is really small i'd like to make them inline, but the linker fails if i try to do this

// util.h
#include <ctime>

inline uint32_t GetTime( );
inline uint32_t GetTicks( );

// util.cpp
#include <util.h>

inline uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

inline uint32_t GetTicks( )
{
    return clock( );
}

or this:

// util.h
#include <ctime>

inline uint32_t GetTime( );
inline uint32_t GetTicks( );

// util.cpp
#include <util.h>

uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

uint32_t GetTicks( )
{
    return clock( );
}

or this:

// util.h
#include <ctime>

uint32_t GetTime( );
uint32_t GetTicks( );

// util.cpp
#include <util.h>

inline uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

inline uint32_t GetTicks( )
{
    return clock( );
}

any of these 3 i try, the linker fails telling me there are 2 prototypes not resolved

i appreciate any help

Recommended Answers

All 5 Replies

Inline functions can be finicky.

As I understand it, because they don't have execution jumps they don't generally work unless they are part of the compilation unit* you are attempting to use them in. This lack of jumps makes the linker unable to find them if they're not already in the object file it's working with. This means that you have to either implement them in your header file, or implement them in every other *.cpp file that you want to use them in.

*A compilation unit is a *.cpp file and all headers #included into it. If you have more than 1 *.cpp file in your project, each one is its own compilation unit.

**Again, this is how I understand them. I may be "out in left field"...

Inlining functions is, first of all, something that the compiler does. So, the first rule is that the compiler has to be able to find the definition of the function (definition = function body). As Fbody said, the compiler only looks at one "translation unit" at a time (a translation unit (TU) is the technical term for what Fbody (wrongly) calls a "compilation unit"). Basically, a TU is what turns into one object file (.o or .obj), it usually comes from the compilation of a single .cpp file (along with all the header-file code/declarations that it includes).

So, if you have the function bodies in a separate cpp file, and compile them separately, the compiler, when compiling the main TU, will not see the definitions of the functions that are in another TU, and thus, will not be able to inline anything.

Now, if you declare a function prototype with the "inline" keyword, it has two effects. First, it _suggests_ to the compiler that this function should be inlined during the compilation. Second, it marks the function for "internal linkage", meaning that the compiler should look for the function definition within the current translation unit in order to perform the linkage (linkage, here, means to replace every call to that function by either a jump to the address of the function or by an inline expansion of the function's body at the call-site). If the compiler does not find the function definition within the current TU, it will give an error.

Then, if you declare the function definitions (in the cpp file) with the "inline" keyword, again, it tells the compiler that this function should have internal linkage. Although it is satisfied at finding the function definition that TU, it will not "export" it (i.e. create a function symbol for external linkage by the linker once all TUs have been compiled). So, in that version (prototype without "inline", and definition with "inline"), the error will come from the linker which will never be able to resolve the reference to that function from your main TU, because that function will never be exported by your compiled util.cpp file.

And, if you mark both the prototype and definition with the "inline" keyword, you get both problems described above.

So, the solution is either:

1) Define the function within its declaration, in the header-file, marking it "inline":

// util.h
#include <ctime>

inline uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

inline uint32_t GetTicks( )
{
    return clock( );
}

2) Put both the declaration and definition in the header-file, and mark either one or both with the "inline" keyword:

// util.h
#include <ctime>

inline uint32_t GetTime( );
inline uint32_t GetTicks( );

uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

uint32_t GetTicks( )
{
    return clock( );
}

3) Include the cpp file at the end of your header file, and mark the functions as "inline" in their declaration:

// util.h
#include <ctime>

inline uint32_t GetTime( );
inline uint32_t GetTicks( );

//Include the cpp file:
#include "util.cpp"

//util.cpp

uint32_t GetTime( )
{
    return GetTicks( ) / 1000;
}

uint32_t GetTicks( )
{
    return clock( );
}

The last version above is a bit awkward (and can cause significant problems if not done correctly), but has the advantage of separating the declaration / definition into two separate files.

commented: good info...:) +5

>>(a translation unit (TU) is the technical term for what Fbody (wrongly) calls a "compilation unit").
:$
Oops. I didn't think that sounded right.

thx, it seems that the rule 'never add a function body into a header file, just the prototype' can't be always respected. i tried to avoid this but since it's the only way, i'll do it.
also i didn't know you could include a cpp file to a header/another cpp file(never seen it used also), thx for the info
thx for your replies guys

Generally, you don't #include *.cpp files in other files. It is an extremely rare occasion that you will want to do that.

*.cpp files should be managed by your IDE's project system or by your make file.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.