What is the gain of "inline"

T

Tom St Denis

Tom St Denis a crit :





Inline functions MUST be written in header files...

If it's trivial enough that being in a header makes sense make it a
macro and uppercase.

Nothing worse than sorting through 250 unsorted .c and .h files trying
to find some random function with a mixed case name because some
jackass thought it was a good idea (bonus points for #ifdef hell).

Tom
 
T

Tom St Denis

Err, yes it CAN go there.

Where do you think inlines are defined?

Or Macros? All code.

Macros with all uppercase names can go in headers [obviously]. If the
function is complex/big enough that making it a macro is iffy then it
probably shouldn't be inlined anyways.

Tom
 
B

Ben Pfaff

Tom St Denis said:
If it's trivial enough that being in a header makes sense make it a
macro and uppercase.

If what I'm doing can be implemented as a function, instead of as
a macro, then I implement it as a function, because functions
have fewer pitfalls than macros.
Nothing worse than sorting through 250 unsorted .c and .h files trying
to find some random function with a mixed case name because some
jackass thought it was a good idea (bonus points for #ifdef hell).

Why don't you use an editor that can jump right to a definition
based on its name? By using inferior tools you indeed are
wasting your time.
 
N

Nobody

If you want to make your program faster, avoid inline. Remember that
a call instruction is very small, and can be predicted in MOST cases
(unless it is a cal through a function pointer).

If the only benefit of "inline" is likely to be elimination of the
function call overhead, don't use it.

OTOH, inlining code into specific contexts can enable various
optimisations which would be precluded if the compiler has to generate
a function which can be called from anywhere.

The most obvious example of this is when the inlined function is called
within a loop, as it allows the use of loop induction (aka strength
reduction) optimisations on the function's body.
 
T

Tom St Denis

If what I'm doing can be implemented as a function, instead of as
a macro, then I implement it as a function, because functions
have fewer pitfalls than macros.

From my experience the sort of things that are short enough to warrant
inlining and tossing in a header are short enough that they can be
done via macros. I've never had occasion to really put a full C
function as "static inline" inside header files.
Why don't you use an editor that can jump right to a definition
based on its name?  By using inferior tools you indeed are
wasting your time.

Last I checked ctags and grep don't work through #ifdef hell.

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. If the body of the
function is longer than the percentage of time taking from the call/
stack frame setup is minimal and making it inlined is near pointless.
Nothing worse than someone using an extreme case to support a rather
silly thought.

I've never have had the need to put a "static inline" function in a
header, and the few times I had a piece of code that was short enough
to warrant forced inlining I just made it a macro.

Sometimes the macro route works better if you're doing something
involving an asm() block. GCC at least can better optimize around them
[register selection, etc] if the code being "called" is actually just
part of the function to start with as opposed to something you call
from a C language point of view...

Tom
 
B

Ben Pfaff

Tom St Denis said:
From my experience the sort of things that are short enough to warrant
inlining and tossing in a header are short enough that they can be
done via macros. I've never had occasion to really put a full C
function as "static inline" inside header files.

Yes, often simple functions can be implemented as macros. I'm
advocating that they not be implemented as macros, because macros
have too many well-known pitfalls, that you surely are aware of.
You are advocating the opposite, but it isn't clear why. Why?
 
I

Ian Collins

Tom said:
Err, yes it CAN go there.

Where do you think inlines are defined?

Or Macros? All code.

Macros with all uppercase names can go in headers [obviously]. If the
function is complex/big enough that making it a macro is iffy then it
probably shouldn't be inlined anyways.

Leave the choice to the compiler. If you use a macro, the code will be
inline, if you use a function it will be inline if the compiler
considers it appropriate (unless you use any compiler specific options
to force the issue).
 
I

Ian Collins

Richard said:
Eric Sosman said:
An effect I've not seen mentioned here is that expanding
a function body in-line may allow some parts to be "executed"
at compile time.
[...]
possibly the case, but I am not sure this is likely to be as
significant/frequent in practice...
Settling the question (either way) would require a good
deal of research. Still, my un-researched impression is that
compilers are pretty aggressive optimizers nowadays, and that
an inlined function body might afford the optimizer more room
to maneuver than the "outlined" version. The compiler working
on an inlined call has information not available to a compiler
building code for a general case. And even if there are no
shortcuts from dead code elimination or from folding in of
known-to-be-constant arguments, there's the possibility of
"cross-talk" between the function body and the caller that
embeds it: Common sub-expression elimination, use of registers
to cache values used in both caller and callee, ...

The opportunities are certainly present. The extent to
which they're used is situational -- and is the hard part to
assess in a general way.

Q: without the "inline", is the compiler free to compile it inline
anyway? I see no reason why not.

It is.
In which case the aggressive nature of compilers and the fact it needn't
bother even inlining it anyway makes the entire conversation 100%
platform dependant.

Correct.
 
T

Tom St Denis

Yes, often simple functions can be implemented as macros.  I'm
advocating that they not be implemented as macros, because macros
have too many well-known pitfalls, that you surely are aware of.
You are advocating the opposite, but it isn't clear why.  Why?

Assuming you wrap your macro with the appropriate do { } while (0)
style brace it should fit anywhere you don't need a return code.

I'm against putting code in a header file because it's just messy and
usually leads to disorganized code trees. If you can keep it
organized all the power to you, but I've been in a few big name shops,
and seem a handful of small shops, and from what I've seen personally,
it usually leads to disasters.

At the very least it should be in a localized header file, e.g. a
typical tree might resemble

src/headers
src/foo
src/bar
src/stuff

If say the files in src/foo/ need an inline function put it in a
header in say src/foo or src/foo/headers as opposed to src/headers...

I'd also challenge most people who use the "inline" keyword to profile
their code and see where time is spent. It's a common mistake for
inexperienced [not saying you are...] developers to outsmart the
situation and not actually profile. I saw a once-called function at
startup be "hella optimized" in really confusing mix of C++/asm all to
shave much less than 1ms off startup time on a server application.
The function was called once during initialization and never seen
again, yet the guy insisted on 3000 lines of template/asm code to
optimize the situation.

Tom
 
I

Ian Collins

Nobody said:
If the only benefit of "inline" is likely to be elimination of the
function call overhead, don't use it.

OTOH, inlining code into specific contexts can enable various
optimisations which would be precluded if the compiler has to generate
a function which can be called from anywhere.

The most obvious example of this is when the inlined function is called
within a loop, as it allows the use of loop induction (aka strength
reduction) optimisations on the function's body.

Another, possibly more common, case is optimisation of register usage.
 
K

Kaz Kylheku

If it's trivial enough that being in a header makes sense make it a
macro and uppercase.

Macros that stand in for C functions are not traditionally written in
upper case.

E.g. getc in a traditional implementation of the C library.
Nothing worse than sorting through 250 unsorted .c and .h files trying
to find some random function with a mixed case name because some

Really; not a single thing worse, Tom?

No grep? No ctags? No mkid? No cscope?


Inline functions provide safety over macros.

/* this converts only ``bar *'' arguments to foo *.
If you want to abuse it, you have to write the cast
at the call site. */

inline foo *the_foo(bar *b) { return (foo *) b; }

/* this converts anything to ``foo *'' that can be,
including integers and, on most compilers,
function pointers, without any cast at the
call site. */
#define the_foo(b) ((foo *) (b))

One possible screwup:

f = the_foo(fun); /* oops should have been the_foo(fun()). */

I mention this one because I recently had macros of this type in a new C
program, and made something similar to the above boo boo.

I wisened up and turned them into inline functions.
 
B

Ben Pfaff

Tom St Denis said:
Yes, often simple functions can be implemented as macros.  I'm
advocating that they not be implemented as macros, because macros
have too many well-known pitfalls, that you surely are aware of.
You are advocating the opposite, but it isn't clear why.  Why?

Assuming you wrap your macro with the appropriate do { } while (0)
style brace it should fit anywhere you don't need a return code.

I'm against putting code in a header file because it's just messy and
usually leads to disorganized code trees. [...]

Why would putting an inline function in a header file cause the
tree to be more disorganized than putting an equivalent macro in
the header file? I can see how an excess of either one could
cause problems, but I don't see how either one would cause more
disorganization than the other.

Here's a decent example of the sort of thing that I would
typically put in a header file:
http://openvswitch.org/cgi-bin/gitw...76c97e5d68e167a551ca3058ed4cb349e67bd;hb=next

Here's another, although really the tag_set_intersects() function
is probably too large:
http://openvswitch.org/cgi-bin/gitw...5dc91a16616199b25d96df7b93dc118e97947;hb=next
 
B

Ben Pfaff

Here are some macros that I invented recently as a way of
improving type safety in my own code. I haven't seen anything
like most of them before, although UP_CAST certainly has a
history:

/* Expands to a void expression that checks that POINTER is an
expression whose type is a qualified or unqualified version of
a type compatible with TYPE (a pointer type) and, if not,
causes a compiler warning to be issued (on typical compilers).

Examples:

int *ip;
const int *cip;
const int **cipp;
int ***ippp;
double *dp;

// None of these causes a warning:
CHECK_POINTER_HAS_TYPE (ip, int *);
CHECK_POINTER_HAS_TYPE (ip, const int *);
CHECK_POINTER_HAS_TYPE (cip, int *);
CHECK_POINTER_HAS_TYPE (cip, const int *);
CHECK_POINTER_HAS_TYPE (dp, double *);
CHECK_POINTER_HAS_TYPE (dp, const double *);
CHECK_POINTER_HAS_TYPE (cipp, const int **);
CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
CHECK_POINTER_HAS_TYPE (ippp, int ***);
CHECK_POINTER_HAS_TYPE (ippp, int **const *);

// None of these causes a warning either, although it is unusual to
// const-qualify a pointer like this (it's like declaring a "const int",
// for example).
CHECK_POINTER_HAS_TYPE (ip, int *const);
CHECK_POINTER_HAS_TYPE (ip, const int *const);
CHECK_POINTER_HAS_TYPE (cip, int *const);
CHECK_POINTER_HAS_TYPE (cip, const int *const);
CHECK_POINTER_HAS_TYPE (cipp, const int **const);
CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
CHECK_POINTER_HAS_TYPE (ippp, int ***const);
CHECK_POINTER_HAS_TYPE (ippp, int **const *const);

// Provokes a warning because "int" is not compatible with "double":
CHECK_POINTER_HAS_TYPE (dp, int *);

// Provoke warnings because C's type compatibility rules only allow
// adding a "const" qualifier to the outermost pointer:
CHECK_POINTER_HAS_TYPE (ippp, const int ***);
CHECK_POINTER_HAS_TYPE (ippp, int *const**);
*/
#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE) \
((void) sizeof ((TYPE) (POINTER) == (POINTER)))

/* Given expressions A and B, both of which have pointer type,
expands to a void expression that causes a compiler warning if
A and B are not pointers to qualified or unqualified versions
of compatible types.

Examples similar to those given for CHECK_POINTER_HAS_TYPE,
above, can easily be devised. */
#define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))

/* Equivalent to casting POINTER to TYPE, but also issues a
warning if the cast changes anything other than an outermost
"const" or "volatile" qualifier. */
#define CONST_CAST(TYPE, POINTER) \
(CHECK_POINTER_HAS_TYPE (POINTER, TYPE), \
(TYPE) (POINTER))

/* Given POINTER, a pointer to the given MEMBER within structure
STRUCT, returns the address of the STRUCT. */
#define UP_CAST(POINTER, STRUCT, MEMBER) \
(CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \
(STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER)))
 
W

Willem

Tom St Denis wrote:
) Assuming you wrap your macro with the appropriate do { } while (0)
) style brace it should fit anywhere you don't need a return code.
)
) I'm against putting code in a header file because it's just messy and
) usually leads to disorganized code trees. ... <snip>

So why are you not against putting code in header files,
when it's in the form of macro's ?


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

ctags and grep suck compared to most frameworks in competent
code editors. However I never found a case where #ifdefs affected ctags in such
a way that you could not find what you wanted.

You obviously haven't worked on highly configurable code before. It's
not uncommon to have platform specific branches of code that include
platform specific macros.

Tom
 
T

Tom St Denis

Assuming you wrap your macro with the appropriate do { } while (0)
style brace it should fit anywhere you don't need a return code.
I'm against putting code in a header file because it's just messy and
usually leads to disorganized code trees. [...]

Why would putting an inline function in a header file cause the
tree to be more disorganized than putting an equivalent macro in
the header file?  I can see how an excess of either one could
cause problems, but I don't see how either one would cause more
disorganization than the other.

Because it's just not where code should go. It also means any file
that includes that file runs the chance of including the inlined code,
wasting space. When I want to look for a function, it should be in
a .c file in a well sorted directory structure.

I guess my real problem is people who tend to do that tend to violate
all sorts of other decent coding practices too..
Here's a decent example of the sort of thing that I would
typically put in a header file:
       http://openvswitch.org/cgi-bin/gitweb.cgi?p=openvswitch;a=blob;f=lib/...

Those are all one-liners which are perfectly well suited for being
macros.
Here's another, although really the tag_set_intersects() function
is probably too large:
       http://openvswitch.org/cgi-bin/gitweb.cgi?p=openvswitch;a=blob;f=lib/...

Same with those.

Why is

static inline int foo(int a) { return a + 3; }

So much simpler than

#define FOO(a) ((a) + 3)

?

At least now when I include foo.h I don't get some function I may not
call... and because it's all uppercase I know to search for FOO in a
header file.

Tom
 
T

Tom St Denis

Tom St Denis wrote:

) Assuming you wrap your macro with the appropriate do { } while (0)
) style brace it should fit anywhere you don't need a return code.
)
) I'm against putting code in a header file because it's just messy and
) usually leads to disorganized code trees.  ... <snip>

So why are you not against putting code in header files,
when it's in the form of macro's ?

Because preprocessor commands are acceptable in header files, because
macros are all uppercase. If you absolutely want your function
inlined, "inline" is actually NOT the way to go. It doesn't force the
compiler to do anything. It could straight up ignore it and just call
the function instead.

So if I had a 1-5 [or so] liner function of code that I needed to
issue as fast as possible, I'd just write a macro and then the
compiler HAS to inline it [well ok, technically no, but it's highly
unlikely the compiler would put it in a function, call it, etc...].

Tom
 
T

Tom St Denis

Macros with all uppercase names can go in headers [obviously].  If the
function is complex/big enough that making it a macro is iffy then it
probably shouldn't be inlined anyways.

Leave the choice to the compiler.  If you use a macro, the code will be
inline, if you use a function it will be inline if the compiler
considers it appropriate (unless you use any compiler specific options
to force the issue).

If it's ambiguous to whether the code would be best inlined or not you
probably should profile. Chances are the function belongs in a
proper .c file on its own.

Tom
 
N

Nick

Stephen Sprunk said:
Nick said:
VLAs don't have to be done on the stack do they? Surely a compiler
could replace:

int bla(size_t sz) {
char p[sz];
/* do lots of things on p - reading that many characters from a file
and hashing them, say */
return result;
}

with

int bla(size_t sz) {
char *p;
p = malloc_with_somthing_on_failure(sz);
/* do lots of things on p - reading that many characters from a file
and hashing them, say */
free(p);
return result;
}

?

Such a simple example appears to comply with the as-if rule, but the
situation gets more complicated when there are multiple potential exits
from the function, including code paths not using "return".

Although I don't "do" C++, isn't that just what a C++ compiler must do
when an object with a destructor goes out of scope? I've often thought
the ability to say "call this function on this object when it goes out
of scope" would be really useful, without going the whole OO hog. It's
hard to come up with a nice syntax for it though.
The easiest way to get "automatic storage duration" is to put a VLA in
the same place as all other objects of "automatic storage duration",
i.e. the stack (on machines that have such). In a sense, VLAs are a
more portable way of providing alloca().

Oh yes, I'm challenging the necessity, rather than the likelihood.
 

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