6

Let's say I have this code (don't mind the fact that SecondsToMinutes and MinutesToHours are carbon copies of each other)

inline float SecondsToMinutes(float seconds)
{
    return seconds / 60.0;
}
inline float MinutesToHours(float minutes)
{
    return minutes / 60.0;
}
inline float HoursToDays(float minutes)
{
    return minutes / 24.0;
}
inline float SeconndsToHours(float seconds)
{
    return MinutesToHours(SecondsToMinutes(seconds));
}
inline float MinutesToDays(float minutes)
{
    return HoursToDays(MinutesToHours(minutes));
}
inline float SeconndsDays(float seconds)
{
    return MinutesToDays(SecondsToMinutes(seconds));
}

Is this valid usage of inline? Does it make sense? Is this good practice? After all, if I recall correctly, inline means that function calls are replaced by function bodies, so

return MinutesToDays(SecondsToMinutes(seconds))

should be equivalent to

return seconds / 60.0 / 60.0 / 24.0

Right?

Or is it better to just use macros for this?

#define EXCHANGE_SEC_MIN(x) (x / 60.0)
#define EXCHANGE_MIN_H(x) (x / 60.0)
#define EXCHANGE_H_D(x) (x / 24.0)
#define EXCHANGE_SEC_H(x) (EXCHANGE_MIN_H(EXCHANGE_SEC_MIN(x)))
#define EXCHANGE_MIN_D(x) (EXCHANGE_H_D(EXCHANGE_MIN_H(x)))
#define EXCHANGE_SEC_D(x) (EXCHANGE_MIN_D(EXCHANGE_SEC_MIN(x)))

Which one is the better practice? Or neither is? I'd like others cents on this.

2501
  • 25,460
  • 4
  • 47
  • 87
  • 7
    Macros are almost *always* the wrong way :-) – paxdiablo Oct 27 '16 at 08:47
  • 2
    Also your macros are wrong: what happens if you use it like `EXCHANGE_SEC_MIN(a+b)`? – mch Oct 27 '16 at 08:49
  • *Macros are almost always the wrong way* In other words, if there is a simple alternative to macro (which in this case is a function, no matter inline or not) prefer to avoid the macro – Leon Oct 27 '16 at 08:50
  • I know that macros are wrong, but to answer the question about `EXCHANGE_SEC_MIN(a+b)` ... What if I created a function that wrapped around the macro? `{ return EXCHANGE_SEC_MIN(x); }` , then you can give a+b as the argument to the actual (non-macro function.) Not that I'd do it that way, since macros are wrong, as you guys said it. – Stephanus Tavilrond Oct 27 '16 at 08:55
  • Inline means "this function could be defined in several translation units". In practice, the definition can be in a header file and you won't get a multiple definitiin error. Nothing more, nothing less. – n. m. could be an AI Oct 27 '16 at 08:59
  • Compilers are so good at deciding when to inline on their own these day - they're often better than humans - that they usually have a special directive for *preventing* inlining. – molbdnilo Oct 27 '16 at 09:03
  • Allright, now I know what to do: use `constexpr` instead of `inline`, and also use -ffast-math, as well as either -O2, -O3 or -Os. – Stephanus Tavilrond Oct 27 '16 at 09:11
  • @StephanusTavilrond `{ return EXCHANGE_SEC_MIN(x); }` is silly, the preprocessor will transform it to `{ return (x / 60.0); }` so it's the same as the original function. – Oktalist Oct 27 '16 at 12:31
  • Unrelated to your actual question, do you realize that `60.0` is a `double` literal and your first function is actually equivalent to `return (float)( (double)seconds / 60.0 );` – KevinZ Oct 28 '16 at 18:58
  • Nope, I did not know that. – Stephanus Tavilrond Nov 02 '16 at 07:01

4 Answers4

7

Is this valid usage of inline? Does it make sense? Is this good practice? After all, if I recall correctly, inline means that function calls are replaced by function bodies, so

Sure it is. You make it more legible which is always good.

return seconds / 60.0 / 60.0 / 24.0

Yes that's how it turns out. Or should. inline is just a hint, the compile just might decide otherwise. But for such one liner, the compiler will inline it.

Macros? Why? If it can be done with functions, why use macros?

themagicalyang
  • 2,493
  • 14
  • 21
  • Thank you for your answer :) I'll be sure to make use of inline functions in the future, now that I know what they are good for. – Stephanus Tavilrond Oct 27 '16 at 08:51
  • 1
    `inline` can turn out pretty useful for such small functions, but caution when doing this on bigger functions. Code bloat is bad. Caution! The compiler will *NOT* reduce your code to a single division, because of floating point math! If you don't mind about breaking compatibility, enable the flag `-ffast-math`. See the difference with and without it on [godbolt](https://godbolt.org/g/7NBXMy). – asu Oct 27 '16 at 09:01
6

Is this valid usage of inline? Does it make sense?

Well, yeah but no.

It doesn't hurt anything at this point but doesn't do what you think it does either.

In an excellent post about inline deft_code correctly says :

It is said that inline hints to the compiler that you think the function should be inlined. That may have been true in 1998, but a decade later the compiler needs no such hints. Not to mention humans are usually wrong when it comes to optimizing code, so most compilers flat out ignore the 'hint'.

So, it doesn't hurt anyone if you do it but the chance your compiler will listen to your hint is practically 0. If it sees fit to inline the code, it will do so itself.

inline nowadays is used mostly for the linker since it allows multiple definitions in multiple compilation units.

If you want to make sure your code is as fast as possible and you have access to C++11 you should use constexpr:

constexpr float SecondsToMinutes(float seconds)
{
    return seconds / 60.0;
}
//etc..
Community
  • 1
  • 1
Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • 1
    Note that `constexpr` is still just a hint. It's not required to be evaluated at compile time unless it is used in a constant expression (e.g. a template non-type argument). It can't be evaluated at compile time if its arguments are not known at compile time, and C++98 compilers could already do constant folding on arguments that are known at compile time. – Oktalist Oct 27 '16 at 12:29
  • @Oktalist Very true, however in this case it's way more likely to be used by the compiler than the `inline` keyword. – Hatted Rooster Oct 27 '16 at 12:30
3

inline does not mean that function calls are replaced by function bodies. At least it hasn't meant that for the past fifteen-something years: optimizers are now way beyond taking orders from the developer, and will perform inlining whether or not you specified inline.

inline actually means "this function may be defined multiple times, and the linker should sort it out and keep at most a single definition at the end. I'm responsible for ensuring that all definitions are identical".

If you really, really want to enforce inlining (the actual insertion of the function's body inside the caller) yourself, you'll have to use compiler-specific extensions such as __attribute__((always_inline)).

You typically need inline when the functions are defined in a header, since this header will eventually be included in several translation units, thus the definitions will be duplicated. As such, assuming your code is inside a header, this is a good use of inline.

Quentin
  • 62,093
  • 7
  • 131
  • 191
0

Assuming the definitions of your inline functions are visible to the compiler at the point of use (e.g. they are in a header file that is #included as needed in each compilation unit), then your usage is valid.

However, inline is only a hint to the compiler. The standards permit the compiler to ignore that hint, and not inline the function. The criteria by which compilers do not inline functions is highly compiler dependent.

Macros are an alternative, but have other concerns .... including that they don't respect program scope, and it is easy to write macros - deliberately or accidentally - that result in different behaviour than a person might expect. So inline functions are often considered preferable.

Peter
  • 35,646
  • 4
  • 32
  • 74