February 2023

S M T W T F S
   1234
567891011
12131415161718
19202122232425
262728    

Style Credit

Expand Cut Tags

No cut tags
Thursday, November 29th, 2007 12:07 pm
For the C/C++ geeks out there, here's a grumpymaking thing I stumbled upon today.

In a .h file:
void __inline FUNCTION_NAME(mystruct* foo)
{
   foo->addrValid = TRUE; 
}

And therefore, in my .c file:
// HORRIBLE HACK!  Only one .o in an executable can have StupidInclude.h included.
// It defines inline functions and the link step will fail if multiple .o files
// contain those definitions.  But every .o in this type of executable must have the
// app data structure definition... which, for this app, relies on StupidInclude.h.
// Therefore, there can be only one .o in this executable.
#include "echoer.c"
#include "listener.c"
#include "pinger.c"

I know there are ways around this, potentially involving (say) precompiled headers, but this is supposedly a simple proof-of-concept app so I'm not bothering for now. And seriously. Who would release something like that and not get fired? Never mind; I know the answer.
Thursday, November 29th, 2007 08:33 pm (UTC)
Wait; that doesn't seem to make sense. If the functions are actually inlined, why should this actually fail? The .o file should have that code inlined (which means that the function body must be in the .h file, not in a corresponding .c file, so the compiler can have it when it's making the .o file), and it shouldn't end up defining a symbol for it, so multiple .o files shouldn't conflict.

I think your compiler is on the list of things being idiots. It shouldn't be defining symbols in the .o files for the inline functions, and this ought to work right.

Of course, it's possible that I'm completely off-base here. Or that the problem is that the __inline syntax doesn't do what it's supposed to do because of being the wrong thing for this particular compiler.
Thursday, November 29th, 2007 08:47 pm (UTC)
OK, I'll have to think about that one.

I should mention that almost every developer using this .h file will also be using the compiler I'm using. (For the system I'm trying to work with, there are only two compilers that will work at all, and the other one costs over $1000.) The guys who wrote that .h obviously didn't try it out with multiple object files.
Thursday, November 29th, 2007 09:07 pm (UTC)
It's also possible that this is related to the inline weirdness in GCC (if that's the "doesn't cost over $1000" compiler). GCC defined the __inline keyword before C99 standardized "inline", and the semantics are subtly different (and, iirc, though my recollection is very hazy, this is one of the places where that's true), and I think that the more recent versions of GCC have changed the definition to match the C99 standard.

If that's true, there are compiler flags to use the "other" behavior which may be relevant. It is also possible that a "#define __inline SOMETHING" hack before including the relevant header files will make things work.

Oh, wait a minute. Right. I decided to check and see how we handle this in our libraries, and realized that this is a stupidity on the part of those library developers -- for this to work right, that function needs to be declared static as well as __inline. A rough hunch is that "#define __inline static __inline" will do the right thing, though that's an ugly hack that breaks if __inline is already a preprocessor macro. (Then you'd need "#define old_inline __inline; #undef __inline; #define __inline static old_inline" or somesuch atrocity.)

IMO, if you've got any kind of support at all for this library, I'd send them a "WTF?" email. :)
Thursday, November 29th, 2007 09:15 pm (UTC)
Ohhhhh yes: static __inline would be great. It's what I had hoped to see when I looked in that .h file (that, or macros).

I'm using gcc, yep. Got it in one. :-)
Thursday, November 29th, 2007 09:46 pm (UTC)
Hah -- I was right about this being related to the GCC/inline weirdness, I think. See this post for a review of the issues.

In C99, "inline" means, roughly, the same thing as "static inline". However, GCC still defaults to using the pre-C99 meaning, where it's only a compiler hint with no actual semantic meaning (and so externally-visible symbols should still get emitted).

Passing the -std=gnu99 option to GCC, if you're using a sufficiently recent version, should do the trick (though it may cause other problems).

(I will note that this is all predicated on GCC treating "inline" and "__inline" as identical, which I think is the case, but I'm not absolutely certain of it.)
Friday, November 30th, 2007 06:18 am (UTC)
Cool! Thanks for the link.

It would be spectacularly awful if "-std=gnu99" were incompatible with this system. I wouldn't put it past 'em. But I haven't tried it yet. Other things ate my afternoon. :)
Thursday, November 29th, 2007 09:08 pm (UTC)
Can you modify this .h file? If so, why not just make it a macro?
Thursday, November 29th, 2007 09:13 pm (UTC)
Nope. That'd be the "right" solution, I think.

Friday, November 30th, 2007 04:49 am (UTC)
Yeah, "static inline" is the right thing for gcc generally, I think.

The GNU/C99/C++ handling of non-static "inline" or "extern inline" is a confusing enough situation that I always stick with "static inline" these days and don't think about it too hard.... If you get stuck using another compiler in addition to GCC, things may get annoying (like, the Sun compiler will always put a static copy of the function in the object file, even if you don't use it), but it should still work.

So, "#define __inline static __inline__", "#include <stupid.h>", "#undef __inline" in case you include a system header later that might try using __inline more reasonably.
Friday, November 30th, 2007 06:17 am (UTC)
Yeah, I should try that. Or, what the heck, #include file.c works pretty well for now.

I'd'a thunk with probably over ninety percent of their developers on GCC, they'd have clued in. But obviously I'd'a thunk wrong. :-)
Friday, November 30th, 2007 06:30 am (UTC)
Maybe I am being stupid. But I am pretty sure that your problem is that this is not declared static. This works great for some not-particularly-pleasant functions like

static inline int64_t
atomic64_add(atomic64 *a, int64_t b)
{
    int64_t i;

    i = b;
    __asm__ __volatile__( LOCKPREFIX "xaddq %0, %1" : "+r" (b), "+m" (a->value) : : "memory");

    return (b + i);
}


Friday, November 30th, 2007 06:45 am (UTC)
That would be exactly my problem, yes. It's in a header file I cannot modify, and I sure do wish they had chosen to put that little word in there.

Brooks notes above that this is a GCC holdover from the days when __inline hadn't been standardized. Still, since GCC is by far the major compiler in use for this code, I wish the library vendor had TRIED it.
Friday, November 30th, 2007 07:20 am (UTC)
You can fix this problem without modifying the header file. Make a file, static_override.h or something, containing a line that redeclares the function properly, like so:

static inline void FUNCTION_NAME();

Now just make sure that you include static_override.h before you include the broken one.