GCC does not "infer" that it's a C++ header file. By the time the compiler is processing the contents of the header it's not a separate file anymore, it's been combined with the main source file by the preprocessor (which happens before any compilation as either C or C++.)
The preprocessor simply includes the content of my_callback.h in the translation unit that says #include <my_callback.h>. If that translation unit is a C++ file being compiled by the C++ compiler, then the contents of my_callback.h are compiled (along with the rest of the translation unit) as C++. If it's a C file being compiled as C, then the contents of my_callback.h are compiled as C. That's it. There's no inference of anything at the granularity of individual headers. *
You are including a C header in a C++ translation unit. Despite their similarities, they are different languages. If you want the header to be valid as part of a C++ translation unit (declaring the functions with the desired linkage) then you need extern "C" to say that the functions use "C" linkage (meaning, among other things, the names are not mangled.) If you want the header to be valid in both C and C++ translation units (declaring the same functions with the desired linkage,) then you need to use #ifdef around the bits that are not valid C. That is your job, not the compiler's.
The compiler does not, and should not, "implicitly [give] it C++ linkage," any more than saying #include <foo.txt> should declare the contents of the text file as a const char.
It is not just gcc and g++ that do this, it's how it's meant to work. You still seem to be blaming gcc for doing what it's meant to.
* GCC will sometimes infer the language to be used from the file extension, but only of files named on the command line. It will not infer a different language for separate files included by the preprocessor. See Invoking G++ for more details.
P.S. The reason that gcc and g++ behave the same is that they are both just drivers that invoke the compiler proper, the difference is that g++ automatically adds -lstdc++ and some related linker options when invoking the linker, and if no explicit -x option is given g++ assumes -x c++ (see the link above for a more accurate explanation.)