1

Environment is Microsoft Visual C++ 2015 and Windows 7.

Is there anything special about inline extern "C" functions defined in a header? I am consuming an SDK in which one of the headers contain such a beast. In my application I have a lone TU (translation unit) whose only job in life is to include the aforementioned header. That's all. Nothing else is in it. If I dig into the generated object file, I see the extern "C" function being pulled in. This is causing me some unwanted side effects (I will leave out what they are for now, as it might just distract from the main issue).

Why would this happen? There is nothing from the client code (remember my lone TU is empty except for main() entry point and that header) that is triggering this to happen.

UPDATE with a small snippet that might explain better what I am running into:

This is what is actually happening:

FooObj.h

FooObj::FooObj() { }

FooObj::~FooObj() { CallIntoAnotherC_API(); }

SDKHeader.h

#include <FooObj.h>

extern "C" inline void SomeFunc(void* user_data)
{   
    A* obj = static_cast<A*>(user_data);
    obj->CallAnotherFunc(FooObj(33));
}

MyFile.cpp

#include "SDKHeader.h"

int main() { return 0; }

Compiling MyFile.cpp into an executable fails with the linker complaining that CallIntoAnotherC_API is an unresolved external.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ForeverLearning
  • 6,352
  • 3
  • 27
  • 33
  • TU? explain please. – Henno Brandsma May 29 '16 at 18:24
  • Imma sorry, I didn't understand you. Can you not understand what for `inline extern "C"`? – Denis Sologub May 29 '16 at 18:25
  • 1
    @HennoBrandsma: My guess: TU = "translation unit". – Martin R May 29 '16 at 18:27
  • TU - translation unit? Right? That was rhe other commenters question I think - and was not the pnly pbe – Dilettant May 29 '16 at 18:29
  • 1
    *Is there anything special about `inline extern "C"` functions defined in a header?* In a word, no. *Why would this happen?* What exactly? Unspecified unwanted side effects? – n. m. could be an AI May 29 '16 at 18:41
  • 1
    @n.m.I am trying to understand why references to that function show up in the compiled object file when the CPP file that includes this header has no references to *anything* in that header. I am missing something. – ForeverLearning May 29 '16 at 18:43
  • 3
    Look hard at [Is `inline` without `static` or `extern` ever useful in C99](https://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99). It covers the issue from the viewpoint of the C system. See also [extern inline](https://stackoverflow.com/questions/216510/extern-inline), which may be more apposite still. Basically, in C, one source file can contain `extern inline …function definition…` and this file will contain a non-inline function for the inline-able function. – Jonathan Leffler May 29 '16 at 18:53
  • @JonathanLeffler Thanks for the links. I will read them now. I have also updated my post to better explain what I am running into. – ForeverLearning May 29 '16 at 19:08
  • Looking at the extra information, the `extern "C"` bit may be going to alter things. It may just create an actual function with C-style linkage (meaning that the name is not 'mangled' to give you type-safe linkage as C++ normally does) that can be used where the `inline` function can't be inlined. But why it is in a file that contains just a `int main() { return 0; }` is more mysterious. It isn't clear (to me) what global variables are being linked/initialized before `main()` runs, or destroyed after it completes. – Jonathan Leffler May 29 '16 at 19:15
  • @JonathanLeffler _But why it is in a file that contains just a int main() { return 0; } is more mysterious._: That's what bothers me too. Picking up on your last point, were you implying that there must exist some unseen piece of code that *calls* `SomeFunc` explicitly for this situation to arise? – ForeverLearning May 29 '16 at 19:23
  • There has to be some more code in `FooObj.h` — either directly or included. Having inline definitions of a constructor and destructor won't work unless there's also the class definition around for the compiler to work with. There may be some details in the class definition that account for what's happening, or some other code in the header that accounts for it. It's good to create an MCVE ([MCVE]). I fear that you've gone a little _too_ minimal in the (first update to the) question, forgoing the 'complete' and 'verifiable' aspects of an MCVE. – Jonathan Leffler May 29 '16 at 19:30
  • @JonathanLeffler I posted an answer and it seems to explain the situation but I can't understand it yet! – ForeverLearning May 29 '16 at 20:40
  • is the implementation of `CallIntoAnotherC_API()` actually being supplied to the linker ? – M.M May 29 '16 at 22:37
  • 1
    I would strongly recommend NOT using `inline` in a header to be shared between C and C++, because it has different semantics in each of C++, ISO C, and GNU C. (no idea what MSVC's C compiler does with it) – M.M May 29 '16 at 22:40
  • @M.M I spun off another [thread](http://stackoverflow.com/questions/37515821/linker-error-with-extern-c-inline-function) to isolate the issue a bit further. – ForeverLearning May 29 '16 at 23:12

1 Answers1

0

Jonathan Leffler! Thank you very much for pointing me in the right direction. I found out what the problem is and its super weird to say the least. In the SDKHeader.h snippet I posted above, there is an extraneous declaration of SomeFunc like so:

#include <FooObj.h>

// I don't know why this declaration exists but its presence is
// causing the compiler to include SomeFunc and everything it references
// in the object file causing eventual linker errors! Also notice that
// this declaration even misses the "inline" keyword.
extern "C" void SomeFunc(void* user_data);

extern "C" inline void SomeFunc(void* user_data)
{   
    A* obj = static_cast<A*>(user_data);
    obj->CallAnotherFunc(FooObj(33));
}

Removing this extraneous declaration gets rid of the linker errors and also prevents the bogus symbol from showing up in the object file.

ForeverLearning
  • 6,352
  • 3
  • 27
  • 33
  • To avoid modifying the SDK header, what happens if you pre-declare this function the way you want it before you `#include` the header? Like `extern "C" inline void SomeFunc(void* user_data);` or even `inline void SomeFunc(void* user_data);`. Perhaps this will convince the compiler to use the `inline` version of the function and ignore all the misleading `extern` versions that come after it in the `#include` file? – Malvineous May 30 '16 at 07:58