22

Browsing among some legacy code I've found such function:

static inline bool EmptyFunc()
{
    return (void*) EmptyFunc == NULL;
}

What are the differences from this one:

static inline bool EmptyFunc()
{
    return false;
}

This code was created to compile under several different platforms, like PS2, Wii, PC... Are there any reason to use the first function? Like better optimization or avoiding some strange compiler misbehavior?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 4
    I'm thinking it's because if you just returned `false`, the compiler would be free to optimize away that function... but then anywhere that actually used it should prevent the same optimization. Hmm. Where is `EmptyFunc` used? Also, why the cast to `void*`? That doesn't make sense for function pointers... – Cameron Apr 25 '13 at 06:25
  • 6
    Just a guess but it looks like they are trying to force the compiler to generate a non-inlined version of the function. This can happen when you take a pointer to a function. – Captain Obvlious Apr 25 '13 at 06:29
  • 2
    `EmptyFunc` was used as a callback in user input registering procedure, which would go through each registered callback and mark corresponding event as triggered when given callback returns true. – Vytis Valentinavičius Apr 25 '13 at 06:30
  • But either way, address of this function would be passed (and saved) to at least one of input registering procedures, so compiler should not inline it anyway? – Vytis Valentinavičius Apr 25 '13 at 06:32
  • 3
    @CaptainObvlious, there is nothing in the first one that would actually prevent a compiler from optimizing away the function when called. Perhaps there are some compilers which don't, but there's nothing fundamental there blocking it. – edA-qa mort-ora-y Apr 25 '13 at 06:37
  • 1
    @CaptainObvlious: Actually, the cast isn't necessary for comparing to `NULL` (at least, [on GCC](http://ideone.com/f1KH4z)) -- and [a function pointer isn't the same as a data pointer](http://stackoverflow.com/a/5579907/21475) and technically shouldn't be cast to `void*`. @edA-qa: Good point. – Cameron Apr 25 '13 at 06:40
  • 2
    Having seen many "PS2, Wii, PC" codebases, my growing suspicion is that no one ever checked if this code made any sense. – Drew Dormann Apr 25 '13 at 06:40
  • 5
    Another option may be bad coding. – BЈовић Apr 25 '13 at 06:43
  • 2
    To me this looks like a hack written for a specific reason (perhaps/probably to work around a specific compiler bug on a specific platform?). What's really fishy is that the original author didn't document it though. – syam Apr 25 '13 at 06:44
  • 2
    *"What are the diferences from this one:"* @syam you nailed it. The second one is self-documenting. – Drew Dormann Apr 25 '13 at 06:45
  • @VytisValentinavičius: The compiler might still inline it (wherever it's called directly), however it won't be able to optimize it away (most likely) and so the function code will be emitted nonetheless. – Matthieu M. Apr 25 '13 at 06:48
  • @Cameron Doh! You're right. WTH was I thinking. – Captain Obvlious Apr 25 '13 at 08:48

2 Answers2

10

Semantically both functions are the same: they always return false*. Folding the first expression to a constant value "false" is completely allowed by the standard since it would not change any observable side-effects (of which there are none). Since the compiler sees the entire function it also free to optimize away any calls to it and replace it with a constant "false" value.

That is, there is no "general" value in the first form and is likely a mistake on the part of the programmer. The only possibility is that it exploits some special behaviour (or defect) in a specific compiler/version. To what end I don't know however. If you wish to prevent inlining using a compiler-specific attribute would be the correct approach -- anything else is prone to breaking should the compiler change.

(*This assumes that NULL is never defined to be EmptyFunc, which would result in true being returned.).

edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267
  • 1
    +1 This is also my feeling that it is to work around a compiler problem (I've seen worse workarounds for buggy compilers, but *at least* the code was documented, unlike here!). – syam Apr 25 '13 at 06:51
3

Strictly speaking, a function pointer may not be cast to a void pointer, what happens then is outside the scope of the standard. The C11 standard lists it as a "common extension" in J.5.7 (I suspect that the same applies in C++). So the only difference between the two cases in that the former is non-portable.

It would seem that the most likely cause of the former version is either a confused programmer or a confused compiler. We can tell for certain that the programmer was confused/sloppy by the lack of an explaining comment.

It doesn't really make much sense to declare a function as inline and then try to trick the compiler into not inlining the code by including the function address in the code. So I think we can rule out that theory, unless of course the programmer was confused and thought it made sense.

Lundin
  • 195,001
  • 40
  • 254
  • 396