Function pointers are a great tool for untangling balls of code and level-izing different components based upon dependencies in a large project. Rather than having to wait until all code is logically refactored, you can poke function pointers to higher-level functionality down into lower-level libraries to remove the physical link-time dependency and/or circular dependency loops.
There are other tricks you can use if your higher-level code is written in C++. You can take advantage of static initializers to do your function pointer poking for you instead of having to manually do it all in main() or some other point of initialization, potentially creating other physical dependencies. (As long as no other static initializers depend on the function pointers being in place, because order of execution is not guaranteed.) e.g.:
There are other tricks you can use if your higher-level code is written in C++. You can take advantage of static initializers to do your function pointer poking for you instead of having to manually do it all in main() or some other point of initialization, potentially creating other physical dependencies. (As long as no other static initializers depend on the function pointers being in place, because order of execution is not guaranteed.) e.g.: