Why platform-specific functions are passed by pointer?

In the non-specific code, Casey uses various pointers to functions that the platform layer must set. Why don't directly use classic functions, and directly call them? It's what happens with the "DEBUG*" functions, they are not passed as pointer, but called directly by the game, so why?

Edited by Terans on Reason: Initial post
It could be done that way. Just export platform functions from main exe file and in game dll use them.

But there is a disadvantage - you cannot choose which platform function to use depending on some condition. For example, you might want to substitute actual function with "no-operation" - empty function. If game dll directly links to exe and calls function directly, you cannot override (or it is very hard), or it requires complex conditions in every single function. Passing function pointer this makes it trivial - just pass different function pointer.

More importantly this is disadvnatage when renderer was split of game/platform layers into separate dll. This way game does not care is it rendered using OpenGL, Direct3D or software renderer. Ability to pass different function pointers for renderer makes platform to choose whichever renderer to use and game just uses it without knowing what it uses.


Whaaaaat?

You are actually saying that I don't have to pass a ton of pointers to the dll? That is sweet! :D

I tried messing around with __declspec(dllexport/dllimport) but I can't get pass the linker...
Can you give me a pointer as to how that can be done? :)
main.c:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <windows.h>
#include <stdio.h>

__declspec(dllexport) void main_fun()
{
    printf("Hello from main.exe\n");
}

int main()
{
    HMODULE m = LoadLibraryA("library.dll");
    void (*fun)() = (void*)GetProcAddress(m, "library_fun");

    printf("Calling library_fun\n");
    fun();
    printf("Back in main()\n");
}


library.c:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

void main_fun();

__declspec(dllexport) void library_fun()
{
    printf("Hello from library.dll\n");
    main_fun();
    printf("Finishing library_fun()\n");
}


Compiling:
1
2
cl main.c
cl /LD library.c main.lib


Output of running main.exe:
1
2
3
4
5
Calling library_fun
Hello from library.dll
Hello from main.exe
Finishing library_fun()
Back in main()


Note that __declspec(dllexport) or dllimport is not really needed. That's just one way how to export symbols. You can instead do /EXPORT or /DEF in linker arguments. It's your choice. They all do same thing.

Edited by Mārtiņš Možeiko on
That's awesome!
Thanks so much for the in-depth explanation! :)
Thank you for a really awesome answer! :)