What is the gain of "inline"

T

Tom St Denis

I think he decided "inline" is bad and is now trying to justify it.
Most of his arguments against inline apply to macros.

Pros for functions:

- More traditional look that makes them easier to read

Cons for functions:

- Code bloat (*)
- Affects compile time
- Prevents trivial asm mappings (for when performance matters most)

Pros for macros:

- Doesn't affect compile time
- No bloat [not compiled when not used]
- Allows for trivial asm mappings (variables are local)

Cons for macros:

- Can be harder to read
- Not all functions map well to macros (multi-stmt with return
values...)

(*) Yes, GCC won't include static functions that are not called, but
not all compilers do this, nor is it required by the standard.

So no, I'm not just trying to justify my comments with things that
equally apply to both.

And all people have shown me so far are 1 stmt inlined functions which
could just as easily been done as macros. And nobody has yet been
able to argue they're even needed for performance reasons...

Tom
 
T

Tom St Denis

An addition to Richard's comment, inline may be appropriate for some
platforms and not on others.  One compiler I use (Sun cc) has a -native
switch that selects additional optimisations based on the host running
the compile, so even code that may not appear multi-platform might be.
I'm sure others do something similar.

It may also be an advantage not to have functions inlined in debug mode.
  With macros, you don't have a choice.

If the function is complex enough that debuging becomes a problem, it
probably shouldn't be inline. Either way, tools like gdb CAN debug
through macros.

Generally at the point where you're offering up functions for header
files to be "static inline" its because you know [or should know] that
the function ought to be inlined all the time. It's a function for
performance reason.

For example, I have macros that load values in big/little endian. I
know they're used in performance critical sections so I don't care
what the compiler thinks, they have to be inline to work well.

Whereas, I have wrappers around calloc/malloc/etc to debug memory
problems, and even though the functions are small they're not
performance critical, so they're in their own .c files. Sure I could
make them a trivial "static inline" but why bother? They're for
debuging anyways...

Tom
 
T

Tom St Denis

 > > Don't be so silly. A macro is not the same thing in any shape or form.
 >
 > The sort of thing you'd want to inline would be a short 3 line
 > function anyways, so a macro would work just fine.

No.  Only if each argument is used at most once.

There are ways around that. Store copies in local variables to a new
block e.g.

#define ADD(a,b,c) \
{\
int r = (a) + (b);\
(c) = r;\
}

.... contrived, but you get the point. Sure if you call that with

ADD(*a++,b,*a)

It'll fail, but I'd argue that's just bad function calling style (and
if I'm not mistaken UB).

Tom
 
G

gwowen

Yes, GCC won't include static functions that are not called, but
not all compilers do this, nor is it required by the standard.
....

If the function is complex enough that debuging becomes a problem, it
probably shouldn't be inline.  Either way, tools like gdb CAN debug
through macros.

So GCC/GDB specific feature may be counted when they're a net gain for
your opinion, but must be discounted when they contradict your
opinion. That's disho^H^H^H^H^H^H interesting.
 
M

Michael Foukarakis

On Dec 11, 3:40 am, Nick Keighley <[email protected]>
wrote:
Cons for functions:

- Code bloat (*)
<snip>
- Prevents trivial asm mappings (for when performance matters most)

Do you actually think that compiler writers (for instance, gcc) are
morons? Those problems are practically nonexistent. But then again,
what's stopping you from developing for an obscure platform without a
decent compiler and perhaps even a 7-bit stack alignment..
Pros for macros:

- Doesn't affect compile time

Are we not counting preprocessor time into compilation time nowadays?
- No bloat [not compiled when not used]

Since when is the executable size an issue? There are literally
thousands of applications which are statically built when released, I
never heard anybody complain about that. Yet a single function (which
apparently is small enough for us to consider making it a macro) might
suddenly bring the Apocalypse, if compiled. Give us a god damned
break.
Cons for macros:

- Can be harder to read
- Not all functions map well to macros (multi-stmt with return
values...)

And good luck trying to debug them. The only ones who won't spend an
eternity at it are the ones who've already suffered enough to know
better..
 
N

Nick Keighley

There are ways around that.  Store copies in local variables to a new
block e.g.

#define ADD(a,b,c) \
{\
   int r = (a) + (b);\
   (c) = r;\

}

yes but you can't write true functions- that return things- like that.
And the style is getting increasingly less natural. Why not just pack
it in and write an inline function?

... contrived, but you get the point.  Sure if you call that with

ADD(*a++,b,*a)

It'll fail, but I'd argue that's just bad function calling style (and
if I'm not mistaken UB).

it is
 
N

Nick Keighley

with you here, but that isn't what you've been saying.

Well yeah and no.  Too many macros in one file makes it harder to
maintain, but macros also don't affect compilation speed as much as
inlined functions.  

really? How do you know? Is this "well it's obvious!" or did you
measure something? Off the top of my head I can't see why an inline
function should be significantly more expensive to compile than a
macro is. And the macro is more work in the pp. And I don't think
(correct me if I'm wrong) the pp is a particularly cheap stage of the
translation process.
So the threshold of "when it's worth it" can be a
bit different.

For me, if a function isn't a performance hazard, it stays as a
function in its own .c file, no matter what.

right. Now can we get back to what we were talking about? You are
claiming an inline function is inferior to a macro and I don't think
you've demonstrated it.
 
D

Dik T. Winter

>
> There are ways around that. Store copies in local variables to a new
> block e.g.
>
> #define ADD(a,b,c) \
> {\
> int r = (a) + (b);\
> (c) = r;\
> }
>
> ... contrived, but you get the point.

Works if it is a void function.

Do you have a macro suggestion for which does not evaluate the arguments
more than once:

double dmax(double a, double b) {
return (a >= b ? a : b);
}

?
 
N

Nick Keighley

Pros for functions:

- More traditional look that makes them easier to read

Cons for functions:

- Code bloat (*)

I don't believe this (macros are the same)
- Affects compile time

I don't believe this (macros are the same)
- Prevents trivial asm mappings (for when performance matters most)

could you expand on that? Inserting assembler code inline may well not
work correctly with inline functions. But its is an extension anyway.

Pros for macros:

<snip mirror of inline Cons>

- generic poor-mans templates
- more likely to actually be inlined
Cons for macros:

- Can be harder to read
- Not all functions map well to macros (multi-stmt with return
values...)

in other words you can't write actual functions easily
(*) Yes, GCC won't include static functions that are not called, but
not all compilers do this, nor is it required by the standard.

So no, I'm not just trying to justify my comments with things that
equally apply to both.

I'm afraid I think you are. I don't see why there is significantly
more code bloat or longer compilation times with inline than with
function-like macros.
And all people have shown me so far are 1 stmt inlined functions which
could just as easily been done as macros.

and you keep on ignoring the multiple evaltion probelms and the lack
of type safeness. these are reasons why C++ added 'em in the first
place.

 And nobody has yet been
able to argue they're even needed for performance reasons...

<sigh> as long as we're comparing inline with macros we have already
accepted (rightly or wrongly) that there is a performance
justification.

I've used and eventually over-used inline in C++. Nowadays I'm
reluctant to use inline, mostly for the breaks encapsulation reason,
though slow compilation influences me. But as I remarked elsewhere,
it's another go-faster thingy to have in your tool-kit if you really
need the speed. And profiling shows you need it. (but where do you
find a decent profiler these days?)
 
T

Tom St Denis

with you here, but that isn't what you've been saying.



really? How do you know? Is this "well it's obvious!" or did you
measure something? Off the top of my head I can't see why an inline
function should be significantly more expensive to compile than a
macro is. And the macro is more work in the pp. And I don't think
(correct me if I'm wrong) the pp is a particularly cheap stage of the
translation process.

Macros don't compile, they're preprocessed. So if you don't invoke
the macro the code doesn't go through the compilers parsers.

This is mostly a throwback comment from things like inlined code in C+
+ header class definitions, templates, etc. At the point where you
NEED pre-compiled headers to make a build occur in a 24 hour window,
chances are you're doing something really wrong.

I'm not saying there is NEVER a need for a static inline function, I
just think the coding practice is best avoided when/if possible and
not casually used when it suits ones fancy. And I say that as someone
who has inherited a lot of bad code to work on over the years. This
is a similar argument to "never use goto." Heck I use goto's, but
there are right and wrong ways to do it (forward jumps to error
handling being about the only time I can see to use goto).

Using static inline for functions which are NOT performance hazards is
just bad practice.

Tom
 
W

Willem

Tom St Denis wrote:
) I'm not saying there is NEVER a need for a static inline function, I
) just think the coding practice is best avoided when/if possible and
) not casually used when it suits ones fancy.

The coding practice of using macro's instead of functions is best avoided
when/if possible and not casually used when it suits ones fancy.

) Using static inline for functions which are NOT performance hazards is
) just bad practice.

Using macro's for functions which are NOT performance hazards is just
bad practise.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
T

Tom St Denis

Tom St Denis wrote:

) I'm not saying there is NEVER a need for a static inline function, I
) just think the coding practice is best avoided when/if possible and
) not casually used when it suits ones fancy.

The coding practice of using macro's instead of functions is best avoided
when/if possible and not casually used when it suits ones fancy.

) Using static inline for functions which are NOT performance hazards is
) just bad practice.

Using macro's for functions which are NOT performance hazards is just
bad practise.

I get that you're trying to be smart and sassy, I don't disagree with
you. What I'm trying to hint at is the idea of "just shove code
anywhere and let the compiler sort out the optimization" is bad.
People should be more deliberate in their actions.

Despite what people are hinting at here I never said to never use
inline functions. What I said is for most trivial 1-2 liners macros
work well, and in cases where you are using asm, it's a bit better
since the variables are local in scope. But I also fully recognize
there are times where a proper function is needed. They're not
mutually exclusive!!!

TL;DR; If your code isn't a performance hazard it doesn't belong in a
header file, no matter what form the code takes.

Tom
 
T

Tom St Denis

Mr Pot meet Mr Kettle

I'm not saying he can't disagree with me. It's just the tone I'm
getting off Richard is impolite and frankly I don't have to put up
with it.

It's entirely possible to disagree with someone without resorting to
absurd arguments and inferences to unprofessional behaviour.

Tom
 
N

Nick Keighley

[why wouldn't the same be so for inline- see later as to why I think
this]
I think Nick might know that. But "compilation" time includes this time
in any sane thinkers book.

Actually I was meaning to claim the opposite. The code in a
preprocessor macro *does* need to be compiled.

Consider:-
#define cube(N) ((N)*(N)*(N))

y = cube(a) + cube(b) + cube(c);

This expands in the obvious manner, and then all those multiplies need
to be compiled! Now I was assuming inline worked in a similar fashion
to the #define, the code is compiled anew each time its invoked whilst
Mr StDenis seems to be assuming the code is compiled once then,
presumably the "machine code" is pasted in where needed.

Consider
sum = 0;
for (i = 0; i < m; i++)
sum += cube(i);

Now I submit that an inline version can be optimised more than a non-
inlined version (strength reduction?). A decent compiler will do just
as much work with both versions. I don't think it gains much by pre-
compiling the inline on spec.

Just a minute...

How can precompiling the code lead to code bloat? I really would
expect both versions to end up with the same machine code!

Are you confusing templates with inline? Templates may well generate
multiple versions of the code for each type used and because it is so
easy to do may generate a lot of code. I don't think inline suffers
from this.


yes, you really could screw up with too much stuff in C++ headers. But
C doesn't have templates (maybe C09?) and (I just keep having to say
this!!) inline and function-like macros have exactly the same
overhead! The main cost is reading the same, gigantic, header over and
over again. In what way do macros help you- you've got to read them as
well!

<snip- nothing new>
 
B

bartc

Consider:-
#define cube(N) ((N)*(N)*(N))

y = cube(a) + cube(b) + cube(c);

This expands in the obvious manner, and then all those multiplies need
to be compiled! Now I was assuming inline worked in a similar fashion
to the #define, the code is compiled anew each time its invoked whilst
Mr StDenis seems to be assuming the code is compiled once then,
presumably the "machine code" is pasted in where needed.

I would assume that the code in an inline function is processed once to an
internal form, and it's that internal form which is either duplicated, or
processed repeatedly to generate several lots of code.
Consider
sum = 0;
for (i = 0; i < m; i++)
sum += cube(i);

Now I submit that an inline version can be optimised more than a non-
inlined version (strength reduction?). A decent compiler will do just
as much work with both versions. I don't think it gains much by pre-
compiling the inline on spec.

Just a minute...

How can precompiling the code lead to code bloat? I really would
expect both versions to end up with the same machine code!

Are you confusing templates with inline? Templates may well generate
multiple versions of the code for each type used and because it is so
easy to do may generate a lot of code. I don't think inline suffers
from this.

I tried this:

inline int fib(int n) {
if (n<2)
return n;
else
return fib(n- 2)+fib(n- 1);
}

To inline this properly would generate a huge amount of code. So much so
that gcc gives up on it.
 
K

Kaz Kylheku

Even if it evaluates its argument twice?

I had that problem licked a decade ago, when I developed an assertion
system against multiple side effects in a macro expansion, for the
paranoid. This is a paper tiger.
Right, so having it as a function you need imax, fmax, dmax and perhaps a
few others. On the other hand, once you have fmax you have actually a

This proliferation is not an adequate replacement for proper
polymorphism, like what we have in the operators.

Though it exorcises the demon of multiple evaluation, it has pitfalls
of its own. If you change the types of some arguments, you have to edit
all of the calls. If you don't edit some of them, they will compile
anyway, and so you may be calling imax on a pair of doubles.

This is like going back to the B language, which had separate operators
for floating math.
family of max functions, also those that return the maximum of an int and
a float.

A macro that evaluates twice, but exhibits type polymoprhism, is a
better alternative than a proliferation of different max functions,
in spite of the multiple evaluation risk of the macro version.

Let's see, remember one simple thing---don't place side effects in the
argument---versus remember which member of proliferation of functions to
use when, and keep revising the choice when the surrounding code
changes. Hmm.
 
B

Ben Pfaff

Kaz Kylheku said:
I had that problem licked a decade ago, when I developed an assertion
system against multiple side effects in a macro expansion, for the
paranoid.

Please explain further.
 
K

Kaz Kylheku

Works if it is a void function.

Do you have a macro suggestion for which does not evaluate the arguments
more than once:

double dmax(double a, double b) {
return (a >= b ? a : b);
}

#define max(a, b) (SFX_CHECK(a) > SFX_CHECK(b) ? (a) : (b))

sfx_check will blow up at run-time if a or b look like syntax that may
have side effects.

There is a performance hit (somewhat mitigated by hashing these
expressions and pulling out results from a cache), but once
you are satisfied with the coverage, you can compile it out of
production code.

http://git.savannah.gnu.org/cgit/kazlib.git/tree/sfx.c
http://git.savannah.gnu.org/cgit/kazlib.git/tree/sfx.h

I've never taken the opportunity to use this in a real projec. It's
simpler just be careful when writing C. Don't ever stuff side effects
into contexts that look like arguments to a function.

Even if what looksl like a function really is a function, there are stil
hazards. Side effects in an argument expression, if they interact,
either cause undefined behavior or unspecified behavior.

So even if we use C++ and templates to make the perfect polymorphic
max, which evalautes arguments just once, we are still screwed if
we do things like

max(fun1(), fun2()); /* fun1 and fun2, have side effects, order matters */

max(++*p, (*q)++); /* p and q point to same object */

These look contrived, because they are. But then, so the examples used
to argue against the traditional max macro are also contrived.
 
K

Keith Thompson

Kaz Kylheku said:
I had that problem licked a decade ago, when I developed an assertion
system against multiple side effects in a macro expansion, for the
paranoid. This is a paper tiger.
[...]

This is less than helpful unless everyone consistently adopts your
solution (which you've neglected to share with us).

In practice, multiple evaluation of macro arguments is a real-world
problem (which is mostly addressed by writing macro names in all-caps
to remind the user not to pass arguments with side effects).
 
D

Dik T. Winter

> Despite what people are hinting at here I never said to never use
> inline functions. What I said is for most trivial 1-2 liners macros
> work well, and in cases where you are using asm, it's a bit better
> since the variables are local in scope.

I do not understand this at all. If you want an inline function in asm
I would say that you just state the function in asm; the arguments (which
in that case are the variables) are very local.

I have used a compiler for Algol 68 where the only way to get inline
assembly was to state the function in assembly. Stronger, almost all the
standard operators were defined this way. The compiler itself had no
knowledge about, say, the addition of two integers, it was defined in
source code:

'op' + = ('real' r, s) 'real':
'begin' 'asm'
head 1,s
r1 fadd r,s
'end';

This meant (the head statement) that the assembly consisted of a single
statement with coercions allowed on the operands (that is, it was also
used if one of the operands was integer and the other real). 'r1' meant
that the first (in this case only) part of the result was the result of
the instruction and the remainder stated that a floating point addition
had to be performed on the operands after possible conversion of one of
the operands. So the compiler would compile it (when used for two floats)
to something like:
SA1 R (load R in X1)
SA2 S (load S in X2)
FX6 X1+X2 (floating point add X1 and X2 leaving the result in X6)
but was free to optimise with respect to register allocation etc. When
used with a float and an int it would become:
SA1 I (load I in X1)
PX1 X1 (put exponent on I)
NX1 X1 (normalise)
SA2 S (load S in X2)
FX6 X1+X2

How more local can you get than within a function?

(Yes, with that compiler almost all standard operators were defined in
that way, put in some kind of header file, 'prelude' in the report, which
was precompiled and loader with every compilation. The huge advantage
was that the compiler did not need to distinguish standard operators and
user defined operators.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,438
Messages
2,571,699
Members
48,796
Latest member
Greg L.
Top