inline trouble with -std=gnu99 (gcc)

A

Andreas Eibach

Hi,

me again.
This "project" (lol) compiles without any warnings if -std=gnu99 is NOT
specified.
However, once it is specified, the inline function is treated as if not
there.

line:
gcc -o a.exe -O2 -Wall -std=gnu99 misc.c menu.c main.c

As I learned it long ago, the order of the translation units DOES matter.
Thus, if I have
[misc.c] inline void shortfunc(USHORT x) { ... }
I may use
[menu.c] extern inline void shortfunc(USHORT);

However, this causes major trouble with gnu99 standard.

Here's my code: (sorry 6 files)

--------
[misc.c]
--------
#include "misc.h"
inline void strToUpper (char* s)
{
while (*s)
{
if(*s > 96 && *s<123)
*s-=32;
s++;
}
}
--------
[misc.h]
--------
ULONG somevariable;

--------
[main.c]
--------
#include "main.h"

int main(int argc, char* argv[])
{ return 0; }
--------
[main.h]
--------
/* here's the troublesome extern inline reference, PREVIOUSLY defined in
misc.c */
extern inline void strToUpper (char*);

--------
[menu.c]
--------
#include "menu.h"
void dummy (void)
{ }

--------
[menu.h]
--------
/* adfmenu.h */
extern inline void strToUpper (char*);

-----
OK, that's it so far...
And now I get: (line numbers removed because they may vary)

menu.h: warning: inline function 'strToUpper' declared but never defined
menu.h: warning: inline function 'strToUpper' declared but never defined
main.h: warning: inline function 'strToUpper' declared but never defined
main.h: warning: inline function 'strToUpper' declared but never defined

"Never defined"? Well, there IS some code in strToUpper(), so this warning
is keeping me puzzled...

Thanks for any insights.

-Andreas
 
N

Nick Keighley

This "project" (lol) compiles without any warnings if -std=gnu99 is NOT
specified.

so, presumably, you're deploying gcc as a C89 compiler...
However, once it is specified, the inline function is treated as if not
there.

C89 doesn't have inline functions
line:
gcc -o a.exe -O2 -Wall -std=gnu99 misc.c menu.c main.c

As I learned it long ago, the order of the translation units DOES matter.

I thought you weren't going to use C99?

how peculiar. Preumably that specifies the order to the linker. (I
never
use gcc this way. I compile each .c to a .o the link all the .o's
together)
Thus, if I have
[misc.c] inline void shortfunc(USHORT x) { ... }
I may use
[menu.c] extern inline void shortfunc(USHORT);

However, this causes major trouble with gnu99 standard.

extern inline seems very odd to me...
Here's my code: (sorry 6 files)

--------
[misc.c]
--------
#include "misc.h"
inline void strToUpper (char* s)
{
 while (*s)
 {
     if(*s > 96 && *s<123)
     *s-=32;
     s++;
 }}

this may be a peculiarity of C99 (or gcc) but my experience of inline
is C++ and I wouldn't put an inline function in a separate C file.
I'd expect the inline function to be visible in the compilation
unit.
How else could the compiler inline the code?

--------
[misc.h]
--------
ULONG somevariable;

--------
[main.c]
--------
#include "main.h"

int main(int argc, char* argv[])
{  return 0; }

I'm not even sure what "extern inline" means
extern inline void strToUpper (char*);

--------
[menu.c]
--------
#include "menu.h"
void dummy (void)
{ }

--------
[menu.h]
--------
/* adfmenu.h */
extern inline void strToUpper (char*);

-----
OK, that's it so far...
And now I get: (line numbers removed because they may vary)

menu.h: warning: inline function 'strToUpper' declared but never defined
menu.h: warning: inline function 'strToUpper' declared but never defined
main.h: warning: inline function 'strToUpper' declared but never defined
main.h: warning: inline function 'strToUpper' declared but never defined

"Never defined"? Well, there IS some code in strToUpper(), so this warning
is keeping me puzzled...

Thanks for any insights.

put the code in the header file. At the very least peruse a good C99
tutorial (H&S? The Standard?) and check how inline is supposed to be
used.
 
P

Phil Carmody

Andreas Eibach said:
Hi,

me again.
This "project" (lol) compiles without any warnings if -std=gnu99 is
NOT specified.
However, once it is specified, the inline function is treated as if
not there. ....

Don't do that, it's dumb. Declare but don't define, variables in
header files;

Don't make baseless assertions - it's not previously defined in misc.c.
It's *subsequently* defined in misc.c from misc.c's perspective.

And quite what do you mean by a function being 'extern inline'?
What does gcc mean by it? And, for completeness, ISO C?
Thanks for any insights.

a) Don't do dumb things.
b) Google for ``extern inline gcc''.

Phil
 
A

Andreas Eibach

Phil Carmody said:
Don't do that, it's dumb. Declare but don't define, variables in
header files;

yeah, well, I normally do not do this. But what did you else want to have?
Some other #include statements? ;-) I've tried to break down the code to the
fundamentals.
So I just put in something for the fun of it, so that it's not empty,
yeah...
Maybe I should have pondered a little more about what to actually put in
there, but wth ^_^

-Andreas
 
M

Mark

Andreas said:
yeah, well, I normally do not do this. But what did you else want to
have? Some other #include statements? ;-) I've tried to break down
the code to the fundamentals.
Perhaps this is better :

[misc.h]
extern ULONG somevariable;

[misc.c]
ULONG somevariable = some_default_value;
 
A

Andreas Eibach

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.

-Andreas
 
B

Ben Pfaff

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

[misc.h]
extern ULONG somevariable;

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

Mark's usage is correct.
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)

I guess that you are not using extern correctly, but it is hard
to tell without details.
 
A

Andreas Eibach

Richard Heathfield said:
Here's something a bit better (3 files):

*grin* I hope you got the bit that it was just ONE sample function to have
something to put the "extern" before.
Just picked the shortest I could find :)
/* xstring.c */
#include "xstring.h"
#include <ctype.h>
void upstring(char *s)
{
while(*s != '\0')
{
*s = toupper((unsigned char)*s);
s++;
}
}

Thanks!
Seems I missed toupper() and wrote my own thing because I've never used
ctype.h before :)
(not the most intuitive include name I can think of, rather lets me think of
type defs ;))

-Andreas
 
A

Antoninus Twink

[misc.c] inline void shortfunc(USHORT x) { ... }
I may use
[menu.c] extern inline void shortfunc(USHORT);

However, this causes major trouble with gnu99 standard.

Unfortunately this has been a complete pig's breakfast in gcc. When
inline was standardized in C99, the usage was fundamentally incompatible
with what gcc was already doing (basically, the semantics of "inline
with no extern or static specifier" versus "extern inline" were exactly
reversed). The gcc folks really dragged their heels about changing gcc
to agree with the standard.

However, I think that since version 4.3, gcc's inline agrees with C99,
at least in -std=c99 mode. What version of gcc are you using?
 
J

jameskuyper

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.

An object should be defined with external linkage only if it's going
to be used in multiple translation units. If that's the case, it
should be declared 'extern' in a single appropriate header file, and
#included into all of those translation units, to ensure that they all
are using the same declaration. In particular, misc.h should be
#included into misc.c, even though the declaration in misc.h should be
redundant with the definition in misc.c. The reason for that is to
make sure that you get an error message if the shared declaration is
actually incompatible with the definition, rather than redundant with
it.
 
P

Phil Carmody

Andreas Eibach 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.

Your C programming life is doomed to failure.

If you're not sharing a declaration between multiple .c files,
then you don't even need it to be in a header file. Turning
the extern into a definition is precisely the wrong thing to do.

Phil
 
A

Andreas Eibach

Antoninus Twink said:
[misc.c] inline void shortfunc(USHORT x) { ... }
I may use
[menu.c] extern inline void shortfunc(USHORT);

However, this causes major trouble with gnu99 standard.

Unfortunately this has been a complete pig's breakfast in gcc. When
inline was standardized in C99, the usage was fundamentally incompatible
with what gcc was already doing

You can bet your life on it that it was. Guess why I had to ask here?
Because everything I knew about it was turned by 180 degrees in the new
standard.
(basically, the semantics of "inline
with no extern or static specifier" versus "extern inline" were exactly
reversed).

Yes. I'm quite familiar with the old syntax, but the new one keeps me
puzzled, always keeps me asking "WHY?".
"Why the hell did they create this fuss / this confusion?"

It's as if the term "wheel" would be changed to denote square objects too
;-)
However, I think that since version 4.3, gcc's inline agrees with C99,
at least in -std=c99 mode. What version of gcc are you using?

minGW on Win32, v4.3.0.

-Andreas
 
A

Andreas Eibach

Phil Carmody said:
Your C programming life is doomed to failure.

Don't shoot too quick, will you?
There is always a possibility that you misunderstood something I said.
If you're not sharing a declaration between multiple .c files,

But I do! Very often even.
*Sigh* Sometimes I have a feeling I'm talking Chinese...
then you don't even need it to be in a header file. Turning
the extern into a definition is precisely the wrong thing to do.

I normally had it this way: (but with functions; rarely with variables,
though)
(obvious that I #include the .h into the c, I omitted this bit)

[misc.h]
ULONG myfunc(void); /*original */

[main.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within main.c
*/

and optionally, if I need it elsewhere too:

[menu.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within menu.c
too */

Anything wrong with that?!
I doubt it.

-Andreas
 
S

Seebs

Yes. I'm quite familiar with the old syntax, but the new one keeps me
puzzled, always keeps me asking "WHY?".
"Why the hell did they create this fuss / this confusion?"

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.

-s
 
E

Eric Sosman

Andreas said:
[...]
I normally had it this way: (but with functions; rarely with variables,
though)
(obvious that I #include the .h into the c, I omitted this bit)

[misc.h]
ULONG myfunc(void); /*original */

[main.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within
main.c */

and optionally, if I need it elsewhere too:

[menu.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within
menu.c too */

Anything wrong with that?!
I doubt it.

Not "wrong," but not "good" either. You are declaring
the same thing (myfunc) in three different places, and defining
it in yet a fourth, which gives you lots of opportunities to
make a mistake and have the declarations disagree with each
other (and hence to have at least one of them disagree with
the definition). A comment like

/* make sure this agrees with misc.h and main.h */
extern ULONG myfunc(void);

gives at best an illusion of safety.

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. Sometimes the circumstances compel you to
the duplicated-declaration approach (consider the many Standard
headers that define size_t, for example), but I'd suggest you
avoid it except as a last resort.
 
J

jameskuyper

Andreas said:
....
I normally had it this way: (but with functions; rarely with variables,
though)
(obvious that I #include the .h into the c, I omitted this bit)

[misc.h]
ULONG myfunc(void); /*original */

[main.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within main.c
*/

and optionally, if I need it elsewhere too:

[menu.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within menu.c
too */

Anything wrong with that?!

Yes - you're declaring the same function in three different places
(you're also declaring it in the definition of of the function, but
that's unavoidable, and a different issue). When you have only a small
body of code, the disadvantages of having multiple declarations are
not obvious, but they get to be pretty severe once you've written a
sufficiently large body of code. They all have to match, or the ways
in which your program can malfunction can get pretty bizarre, and
debugging the problem gets very difficult. Once you've got them all
matching, if you ever change one of them, you'll need to change all of
them, for the same reason. This can become a maintenance nightmare.

Everything should be declared in exactly one place; if the declaration
is needed in more than one translation unit (TU), than the place it's
declared in should be a header file, that is shared in all of the TUs
where the declaration is needed, by using #include. It should also be
#included in one TU where it is technically not needed: the place
where the thing is defined - the purpose of this is to ensure that the
definition is compatiple with the header file declaration.

Second issue: the 'extern' on the function declaration is unnecessary:
"If the declaration of an identifier for a function has no storage-
class specifier, its linkage is determined exactly as if it were
declared with the storage-class specifier extern." (6.2.2p5)

A third problem is that the appropriate way to handle this is
different for objects than for functions. For objects with external
linkage, the extern is absolutely necessary.

The reason for this difference is that a function declaration without
a function body always declares a function defined somewhere else. In
contrast, an uninitialized file-scope object declaration that uses
neither the 'static' nor the 'extern' keyword, is considered a
tentative definition. In general, such a tentative definition
automatically becomes an external definition of an zero-initialized
object (6.9.2p2). If you don't use an 'extern' in your header file
declaration, you could have a separate external definitions of the
object in each translation unit - the behaviour of such a program is
undefined.

Can you avoid this problem by preventing the automatic conversion? No.
There's several possible ways to interfere with that conversion, none
of which are good in this context:

a) A prior 'static' file scope declaration of the identifier would
give it internal linkage - which is generally not what you want to
have happen to a declaration you bothered putting in a header file.

b) A following 'static' declaration would make the behaviour undefined
(6.6.2p7), which doesn't do much good, either.

c) A prior or following file scope declaration of the identifier with
an initializer will make it use that initializer, rather than the
default value of 0. This doesn't help avoid the multiple external
definitions problem.
 
P

Phil Carmody

Andreas Eibach said:
Don't shoot too quick, will you?
There is always a possibility that you misunderstood something I said.


But I do! Very often even.
*Sigh* Sometimes I have a feeling I'm talking Chinese...

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.
I normally had it this way: (but with functions; rarely with
variables, though)

Variables and functions behave differently in this respect.
(obvious that I #include the .h into the c, I omitted this bit)

[misc.h]
ULONG myfunc(void); /*original */

[main.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within
main.c */

and optionally, if I need it elsewhere too:

[menu.h]
extern ULONG myfunc(void); /*so i can access myfunc() from within
menu.c too */

Anything wrong with that?!

Plenty, style-wise, and source-code-management-wise. If you change
myfunc to take a parameter in menu.? but forget to change the other
occurences, then you've got untruths in {misc,main}.h. Untruths
which can lead to undefined behaviour. Never duplicate anything
which can't as easily be done in one place.
I doubt it.

How deeply is your head buried in the sand?

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.

Phil
 
P

Phil Carmody

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.

I don't think that's the issue, really. I think the problem is that
gcc forged on ahead with their extension, and when the stds committee
noticed there was a use for the feature, they thought about it, used
a little bit of grey matter, and realised that gcc had implemented
it in *completely* the wrong way.

Lack of dialogue perhaps made the WG think "surely they can't be so
braindead as to implement it with completely unintuitive semantics?!",
but I like to think they'd never have been crazy enough to adopt the
same mistake just because of precedence.

Phil
 
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 ;-)
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'".
Same goes for generalizing statements like "...doomed to failure".

-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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top