inline trouble with -std=gnu99 (gcc)

A

Andreas Eibach

Seebs said:
Long story short, back in the day, there was not good rapport between the
gcc and ISO C communities. There were no gcc people involved in the
standards
work, so their existing practice was somewhat underrepresented.

Heh. Interesting insights, didn't know that. Thanks. :)

-Andreas
 
A

Andreas Eibach

If you are not using the same terminology as the standard and the
rest of us here, then what you say might be indistinguishable from
Chinese.
How deeply is your head buried in the sand?

Deeply enough so I can't hear you anymore I guess ;-)
You have a lot to learn, and unless you demonstrate an attitude showing
a willingness to learn, it's certainly not going to be me who will
waste effort helping you.

Um, I can easily do without, trust me.
So if you want to stop "wasting effort", you may as well do it right now!
Frankly, I don't like your tone too much, it sounds like "everyone needs to
program the way that I do, because otherwise this will be 'doomed to
failure'".

-Andreas
 
A

Andreas Eibach

Eric Sosman said:
It is usually better to declare a function or variable or
type in just one header, and #include that unique header wherever
the declaration is needed, than to scatter multiple declarations
over several headers.

So you're basically saying: do without 'extern' completely?
(at least for functions)

Actually it seems to me that I'm rather attracting multiple definition
errors *BY* #including one and the same foo.h in different TUs!
Supposed myfunc() is needed in each of x.h, y.h and z.h:

[foo.h]
ULONG myfunc();

[x.h]
#include "foo.h"
[y.h]
#include "foo.h"
[z.h]
#include "foo.h"

That's what you had in mind, right?
Looks horribly redundant to me, at first sight...
Since I'm pretty accurate with my 'extern' declarations, I haven't run into
any trouble yet.
For me this is no lesser "awkward", to say the least...but ymmv

-Andreas
 
J

James Kuyper

Andreas said:
So you're basically saying: do without 'extern' completely?
(at least for functions)

"extern" is pointless for functions, and absolutely essential when
declaring objects.
Actually it seems to me that I'm rather attracting multiple definition
errors *BY* #including one and the same foo.h in different TUs!

That would be a danger only if your foo.h contains definitions; it
should only contain declarations, not definitions. Make sure that your
header files do not provide bodies for the functions they declare. Make
sure that any objects declared in a header use 'extern', and are not
initialized. That's all you need to do to avoid this problem.
 
K

Keith Thompson

Andreas Eibach said:
Eric Sosman said:
It is usually better to declare a function or variable or
type in just one header, and #include that unique header wherever
the declaration is needed, than to scatter multiple declarations
over several headers.

So you're basically saying: do without 'extern' completely?
(at least for functions)

Actually it seems to me that I'm rather attracting multiple definition
errors *BY* #including one and the same foo.h in different TUs!
Supposed myfunc() is needed in each of x.h, y.h and z.h:

[foo.h]
ULONG myfunc();

[x.h]
#include "foo.h"
[y.h]
#include "foo.h"
[z.h]
#include "foo.h"

That's what you had in mind, right?

No, you're missing the include guard in foo.h:

[foo.h]
#ifndef H_FOO
#define H_FOO
ULONG myfunc();
#endif /* H_FOO */

[x.h]
#ifndef H_X
#define H_X
#include "foo.h"
#endif /* H_X */

[y.h]
#ifndef H_Y
#define H_Y
#include "foo.h"
#endif /* H_Y */

[z.h]
#ifndef H_Z
#define H_Z
#include "foo.h"
#endif /* H_Z */

This guarantees that each header's contents will be included only once
in each translation unit.

(It would be more natural to use "FOO_H" as the include guard
name for "foo.h"; the problem is that identifiers starting with
'E' are reserved for errno constants, so something like "EDIT_H"
could conceivably create a conflict.)

[...]
 
K

Keith Thompson

James Kuyper said:
That would be a danger only if your foo.h contains definitions; it
should only contain declarations, not definitions. Make sure that your
header files do not provide bodies for the functions they
declare. Make sure that any objects declared in a header use
'extern', and are not initialized. That's all you need to do to avoid
this problem.

In my followup, I missed the "in different TUs" part.

Including the same header in multiple translation units is not
a problem. Including it multiple times in a single translation
unit can cause problems; these problems can be avoided by the use
of include guards.
 
A

Andreas Eibach

Mark McIntyre said:
Andreas said:
Mark said:
Perhaps this is better :

[misc.h]
extern ULONG somevariable;

[misc.c]
ULONG somevariable = some_default_value;
Nah!

I always use "extern" *across files* (e. g. misc.c <-> main.c) but never
between a header and a main file with the same prefix (misc.h<->misc.c)
At least I never did before.

Then presumably you never needed to include a header in another C file. If
you did, you'd find your linker complaining about two definitions of
somevariable

But I did need that. And lo' and behold, I've also run across the multiple
definition problem many times :)
That's why one needs that #ifdef BLAH_H / #define BLAH_H / #endif
preprocessor guff (almost every time).

In a nutshell:
I'd use "extern" for "misc.h" <-> "main.h", "menu.h" <-> "main.h" and the
rest of those combinations...
but NOT:

main.h<->main.c, menu.h <->menu.c and so on.
You get me? That's what I meant by "same prefix".

-Andreas
 
N

Nick Keighley

Deeply enough so I can't hear you anymore ;-)

your loss

Um, I can easily do without, trust me.
So if you want to stop "wasting effort", you may as well do it right now!
Frankly, I don't like your tone too much, it sounds like "everyone needs to
program the way that I do, because otherwise this will be 'doomed to
failure'".

do you apply the same reasoning to everyone else that is correcting
your misconceptions?

Some things in programming are matters of opinion

if (x == 0) z = -1;

or

if (0 == x)
{
z = -1;
}

Others are simply mistakes. Your practice of putting the same text
in different files is error prone. The database people call this
Normal Form. If you store the same information in multiple places
then it *will* go out of sync.

I have access to the source of a project and one header file is
included in
4762 other files. Would you really want to inline that file and have
to maintain
4762 different files? This is admittedly a rather extreme example!

Same goes for generalizing statements like "...doomed to failure".

certain practices, how does it go (from memory):-

"some practices invite errors whilst this practice dials an 0800
number
and orders errors to be delivered directly to your door"
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Keith said:
In my followup, I missed the "in different TUs" part.

Including the same header in multiple translation units is not
a problem. Including it multiple times in a single translation
unit can cause problems; these problems can be avoided by the use
of include guards.

How about putting a templated function definition inside the header?
Example:

#ifndef _foo_hpp
# define _foo_hpp
template<class t>void swap(t&a,t&b){
t c=a;
a=b;
b=c;
}
#endif

In this case, using swap<int> in 2 different TUs will cause a linker
conflict. However, putting the definition in foo.c will cause undefined
references.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkrMbAsACgkQG6NzcAXitM8DiACfeakv2YsDh8NNMBfIahNQwqwT
nl0Amwb3Inev+k1c1cKQRWq9fVlNNvtM
=p93I
-----END PGP SIGNATURE-----
 
J

James Kuyper

Michael said:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1



How about putting a templated function definition inside the header?

This is comp.lang.c; you're thinking of That Other Language.
 
E

Eric Sosman

Andreas said:
So you're basically saying: do without 'extern' completely?
(at least for functions)

You don't need `extern' on a function declaration, but it's
harmless. It may also help to emphasize the point that the
function itself isn't "here," but elsewhere. (We habitually put
lots of unnecessary things in our source to aid readability --
white space, for example, and comments.)
Actually it seems to me that I'm rather attracting multiple definition
errors *BY* #including one and the same foo.h in different TUs!
Supposed myfunc() is needed in each of x.h, y.h and z.h:

[foo.h]
ULONG myfunc();

This is a declaration, but not a definition, so ...
[x.h]
#include "foo.h"
[y.h]
#include "foo.h"
[z.h]
#include "foo.h"

.... these are not "multiple definitions."
That's what you had in mind, right?

Sort of. It's unusual for one header to #include another
merely to obtain a function declaration, because headers seldom
contain things that "use" function declarations. An exception
would be headers containing function definitions (usually with
`inline', which is where this thread got started) which themselves
call myfunc(). More typically, one header #includes another to
acquire its macro definitions and type declarations; the function
declarations are usually of interest only to the .c files that
#include a header.
Looks horribly redundant to me, at first sight...

It's no more redundant that writing `ULONG myfunc();' in
four places, and it's noticeably safer.
Since I'm pretty accurate with my 'extern' declarations, I haven't run
into any trouble yet.

"Never make mistakes" is a splendid policy, but a hard one
to follow. If you've got a team of fifty programmers working on
successive generations of a five million line program over a span
of fifteen years, you'll find that the policy becomes impossible
to follow. That's when you find that reducing the opportunities
for making mistakes will pay off. And even if you're only writing
toy programs of two or three thousand lines, it's just as well to
develop and practice good habits that will be helpful when you get
around to serious programming.

The largest system I've worked on extensively grew to just
under four million lines of mixed C and Lisp, encompassing about
a hundred programs (one huge one, half a dozen large ones, and
the rest modest-sized filters and utilities of various kinds).
This is by no means a "huge" system as such things go, but we
could never have written, debugged, enhanced, extended, and
maintained it if we hadn't taken fullest advantage of every
mistake-avoidance trick available. That's why I value mistake-
avoidance tricks. (Lordy, how I wish we'd had prototypes in
those days!)
 
P

Phil Carmody

Andreas Eibach said:
Deeply enough so I can't hear you anymore I guess ;-)


Um, I can easily do without, trust me.

That's more like head-burried-in-arse, which is even worse than
head-burried-in-sand.

Enjoy being shit at programming. Please get a job in Microsoft,
so you can be an active part of their demise.

Phil
 
P

Phil Carmody

Michael Tsang said:
How about putting a templated function definition inside the header?

There's no such thing.
Example:

#ifndef _foo_hpp
# define _foo_hpp
template<class t>void swap(t&a,t&b){

That's not C. Please evolve a brain.

Phil
 
N

Nick Keighley

So you're basically saying: do without 'extern' completely?
(at least for functions)

rather, "do without extern for functions, you must use it for
objects (data)". I know that logically says the same thing but
the emphasis is odd in your version. You *must* use extern
for objects in header files.
Actually it seems to me that I'm rather attracting multiple definition
errors *BY* #including one and the same foo.h in different TUs!

you are still confused between "declaration" and "definition". (It
took me *years* to sort out- I think C has it backwards). You won't
have multiple definition problems by including header files. Because
A HEADER FILE WON'T HAVE ANY DEFINIONS IN IT!!

int pippo (int x);

isn't a definition it's a declaration.

Supposed myfunc() is needed in each of x.h, y.h and z.h:

[foo.h]
ULONG myfunc();

this isn't a proper prototype. You want
ULONG myfunc(void);

(putting nothing in the brackets *in a declaration* means "takes an
unknown
number of arguments").

[x.h]
#include "foo.h"
[y.h]
#include "foo.h"
[z.h]
#include "foo.h"

That's what you had in mind, right?
Looks horribly redundant to me, at first sight...

how come? If all of x,y and z use myfunc() what simpler
method is there of getting the correct prototype (declaration)
than pulling the right header in?
Since I'm pretty accurate with my 'extern' declarations,

pretty accurate...

I haven't run into
any trouble yet.
For me this is no lesser "awkward", to say the least...but ymmv

it never seems awkward to me
 
A

Andreas Eibach

Nick Keighley said:
rather, "do without extern for functions, you must use it for
objects (data)". I know that logically says the same thing but
the emphasis is odd in your version. You *must* use extern
for objects in header files.

Hi again,

well I never do without reading along information *while* posting here, so
at least I have to admit that the use of extern in functions IS rare.
That's a fact.
And yes too to the fact that the uses in func's and in var's are really
apples & oranges.
Frankly, I had no idea that there is *THAT* much diversity...
you are still confused between "declaration" and "definition". (It
took me *years* to sort out- I think C has it backwards).
have multiple definition problems by including header files. Because
A HEADER FILE WON'T HAVE ANY DEFINIONS IN IT!!

Yes *bangs head* I meant multiple *declaration* problems.
int pippo (int x);

isn't a definition it's a declaration.

Supposed myfunc() is needed in each of x.h, y.h and z.h:

[foo.h]
ULONG myfunc();

this isn't a proper prototype. You want
ULONG myfunc(void);

True. Lazy typist. (/me)
In code, I normally set them. But don't forget, at highest warning level, I
would have warnings there :)
Unfortunately not here, so when "writing code in the wild" and without a
compiler at hand, this happens :)

-Andreas
 
A

Andreas Eibach

James Kuyper said:
"extern" is pointless for functions, and absolutely essential when
declaring objects.

extern in functions and extern in objects are in fact two different pairs of
socks.
Meanwhile, I've (re-)read several sections about this matter.
That would be a danger only if your foo.h contains definitions; it should
only contain declarations, not definitions.

"Should" yes. But what if they do anyway?
(Since this could bring us easily back to the actual topic: inlines. =))
Since inline functions are often found to be both declared *and* defined in
header files, this WILL call for trouble then, won't it?
So it will require anyone using those inlines to think about a strategy how
to avoid ugly errors.

That's another reason why I thought about using the extern (for functions)
way, just *to* avoid this problem.

-Andreas
 
J

jameskuyper

Andreas said:
Yes *bangs head* I meant multiple *declaration* problems.

The point is, multiple definitions would be a problem; but multiple
declarations are not; not so long as they're identical.
 
R

Richard Bos

Nick Keighley said:
you are still confused between "declaration" and "definition". (It
took me *years* to sort out- I think C has it backwards).

Not IMO. To declare is to state _that_ something is, whereas to define
is to state _what_ it is. When Oscar Wilde had nothing to declare except
his genius, he certainly didn't expect to have to explain exactly why
"Earnest" is so hilarious (which was just as well, since, given that it
would have been New York Customs House officers trying to understand the
humour, it would have been completely in vain).

And that's precisely how C has it.

Richard
 
J

jameskuyper

Andreas said:
extern in functions and extern in objects are in fact two different pairs of
socks.
Meanwhile, I've (re-)read several sections about this matter.


"Should" yes. But what if they do anyway?

Headers that contain external definitions are always a design error.
Headers are supposed to be used to share code between multiple
translation units (TUs); if something is not intended to be shared, it
should be defined in the main program files, not the header. If it's
meant to be shared, it will appear in multiple TUs, and for external
definitions that would mean that the behaviour would be undefined.

Headers that define functions or objects with internal linkage define
a separate function or object with the same name in each translation
unit they are #included into. There's rare but legitimate reasons for
doing so, mostly involving inline functions, as you pointed out.
(Since this could bring us easily back to the actual topic: inlines. =))
Since inline functions are often found to be both declared *and* defined in
header files, this WILL call for trouble then, won't it?

There are three possibilities:

The inline functions functions are declared 'static': no problem, the
functions have internal linkage.

The inline functions have implicit external linkage: no problem. The
key point is that the function definition in the header becomes an
inline definition, which is NOT an external definition (6.7.4p6).
However, when this is the case, you must make sure that one (and only
one!) translation unit also has an external definition for the
function, because each time such a function is called, the
implementation is free to decide whether to use the inline definition
from the header file, or the external definition provided elsewhere.
That's what went wrong with your code. You provided an inline
defintion, and you declared an external definition, but nowhere in
your code did you actually define an external definition.

The inline functions are explicitly declared 'extern'. Big problem, if
this occurs in more than one translation unit. Therefore, this should
NEVER be done in a header, because the mail point of having a header
file is to put it into multiple translation units.
So it will require anyone using those inlines to think about a strategy how
to avoid ugly errors.

That's another reason why I thought about using the extern (for functions)
way, just *to* avoid this problem.

As you see above, putting 'extern' on an inline function declaration
in a header file CAUSES the very problem you're trying to avoid.
 
A

Andreas Eibach

jameskuyper said:
There are three possibilities:

The inline functions functions are declared 'static': no problem, the
functions have internal linkage.

Yes, but IMHO this would not solve my problem, because then I may only use
the inline function in *one* TU.
(Unless I'm thinking the wrong way here)
The inline functions have implicit external linkage: no problem. The
key point is that the function definition in the header becomes an
inline definition, which is NOT an external definition (6.7.4p6).

Heck yeah. _That_ was the tricky bit to remember. Thanks for refreshing my
memory again...
However, when this is the case, you must make sure that one (and only
one!) translation unit also has an external definition for the
function, because each time such a function is called, the
implementation is free to decide whether to use the inline definition
from the header file, or the external definition provided elsewhere.
That's what went wrong with your code. You provided an inline
defintion, and you declared an external definition, but nowhere in
your code did you actually define an external definition.

Yeah. That might be it.
So this should look like this:

(TU#1)
inline void blah(int x) {/* code */ }

*AND*
(TU#2)
extern inline void blah(int x);

*AND*
(TU#3)
extern inline void blah(int x) {/* code */ }

aw'ite?

The tricky bit is having the /* code */ TWICE.
Outside this special case, you'd fear a duplicate definition error.
But this automagical transition of the linkage class (6.7.4p6) turns things
vice-versa, of course.
The inline functions are explicitly declared 'extern'. Big problem, if
this occurs in more than one translation unit. Therefore, this should
NEVER be done in a header, because the mail point of having a header
file is to put it into multiple translation units.
ACK.

As you see above, putting 'extern' on an inline function declaration
in a header file CAUSES the very problem you're trying to avoid.

Yeah, I even knew that before that it's due to a dupe problem. Just needed
to know which exactly :)

Thanks for one of the most insightful posts ever in this discussion.

-Andreas
 

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
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top