473,320 Members | 1,977 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Inlines with external linkage

Hi,

I have the following code:

/******************************** file1.c
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/****************************************

/******************************** file2.c
#include <iostream>

inline int testfunc() {
return 2;
}

void dummy() {
std::cout << testfunc();
}
/****************************************

Now, I wasn't sure exactly what this code should do (by 'this code', I
mean the program obtained by compiling these two files and then linking
their respective object files). I was thinking it would output 12 or
there'd be an error of some description.

However, depending on the order of linkage, it succeeds and outputs 11
or 22. In other words, the linker is somehow removing multiple
definitions of this inline function and resolving both 'calls' to one of
them... but surely if it's inline, it will be dealt with at compile time
and the linker should have nothing to do with it? I know that 'inline'
doesn't guarantee inlining, but surely the linker can't decide not to
inline it, since surely that decision must be made at compile time. It
only behaves as expected if I force internal linkage on the testfuncs
with the 'static' keyword. There's something going on, because the
linker obviously 'doesn't mind' that this function has been multiply
defined, which I assume is because the compiler needed to have a
definition in each translation unit in order to be inlined it. I'm
confused though how the linker is resolving these multiple definitions
though. Any insight into inlines and external linkage etc. would be
greatly appreciated.

FYI, I'm using g++.

Thanks,

--

Richard Hayden
http://www.dx-dev.com
Jul 22 '05 #1
47 3783
Richard Hayden wrote:
SNIPPED


OK, I notice I mucked up the comments there, please ignore the fact that
there's no terminating */'s.

--

Richard Hayden
http://www.dx-dev.com
Jul 22 '05 #2
* Richard Hayden:

/******************************** file1.c
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/****************************************

/******************************** file2.c
#include <iostream>

inline int testfunc() {
return 2;
}

void dummy() {
std::cout << testfunc();
}
/****************************************


You have Undefined Behavior (TM) because you have two different
definitions of the same external linkage 'inline' function.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #3

"Richard Hayden" <ra***@doc.ic.ac.uk> wrote in message
news:cb*********@sparta.btinternet.com...
Hi,

I have the following code:

/******************************** file1.c
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/****************************************

/******************************** file2.c
#include <iostream>

inline int testfunc() {
return 2;
}

void dummy() {
std::cout << testfunc();
}
/****************************************

Now, I wasn't sure exactly what this code should do (by 'this code', I
mean the program obtained by compiling these two files and then linking
their respective object files). I was thinking it would output 12 or
there'd be an error of some description.

However, depending on the order of linkage, it succeeds and outputs 11
or 22.


Undefined behaviour as per 3.2/5.

The One Definition Rule allows you to repeat the definition of an inline
function as long as:
1) They appear in different translation units.
2) The are token-for-token identical and the meanings of these tokens
should be the same in both translation units.
Jul 22 '05 #4
Alf P. Steinbach wrote:
* Richard Hayden:
/******************************** file1.c
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/****************************************

/******************************** file2.c
#include <iostream>

inline int testfunc() {
return 2;
}

void dummy() {
std::cout << testfunc();
}
/****************************************

You have Undefined Behavior (TM) because you have two different
definitions of the same external linkage 'inline' function.


Hi,

Thanks for your reply.

I understand what you mean in that case, so I have amended my code to:

/*******************test1.c*******************/
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/*********************************************/

/*******************test2.c*******************/
#include <iostream>

extern int testfunc();

void dummy() {
std::cout << testfunc();
}
/*********************************************/

Surprisingly, it works as expected, i.e. the output is 11. How is this
occuring? Surely the linker must be doing some of the compiler's work
here in order to inline testfunc in the call in test2.c?

Thanks,

--

Richard Hayden
http://www.dx-dev.com
Jul 22 '05 #5

inline

is an abbreviation of:

static inline

-JKop
Jul 22 '05 #6
JKop wrote:
inline

is an abbreviation of:

static inline

-JKop


Really? I didn't think this was the case anymore.

--

Richard Hayden
http://www.dx-dev.com
Jul 22 '05 #7
* Richard Hayden:

* Alf P. Steinbach wrote:
You have Undefined Behavior (TM) because you have two different
definitions of the same external linkage 'inline' function.

I understand what you mean in that case, so I have amended my code to:

/*******************test1.c*******************/
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/*********************************************/

/*******************test2.c*******************/
#include <iostream>

extern int testfunc();

void dummy() {
std::cout << testfunc();
}
/*********************************************/


Well this is simply invalid code. But it's fine details; I was
surprised when I saw the combination of 'inline' one place and
'extern' another place and had to look it up. §3.3/3: "An inline
function shall be defined in every translation unit in which it
is used", which is repeated in §7.1.2/4 which continues: "and
shall have exactly the same definition in every case. ... If a
function with external linkage is declared inline in one
translation unit, it shall be declared inline in all translation
units in which it appears; no diagnostic is required".
^^^^^^^^^^^^^^^^^^^^^^^^^

The extern'ness of inline functions is simply that they are (or can
be) visible to the linker so the linker can remove all but one
occurrence -- and you don't know which one, so must be identical.

Surprisingly, it works as expected, i.e. the output is 11.
Still UB...
How is this
occuring? Surely the linker must be doing some of the compiler's work
here in order to inline testfunc in the call in test2.c?


See above. But with your code it isn't required to. Because it's UB.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #8
* Richard Hayden:
JKop wrote:
inline

is an abbreviation of:

static inline

-JKop


Really? I didn't think this was the case anymore.


It isn't, and AFAIK never was.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #9
Alf P. Steinbach wrote:
[SNIPPED]


Many thanks for your help, I now believe I understand.

Kind Regards,

--

Richard Hayden
http://www.dx-dev.com
Jul 22 '05 #10
JKop wrote:
inline

is an abbreviation of:

static inline
...


No.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #11
Andrey Tarasevich posted:
JKop wrote:
inline

is an abbreviation of:

static inline
...


No.


You're educated. I wish I could make statements and provide support just
like you.

-JKop
Jul 22 '05 #12
Alf P. Steinbach posted:
* Richard Hayden:
JKop wrote:
> inline
>
> is an abbreviation of:
>
> static inline
>
>
>
> -JKop


Really? I didn't think this was the case anymore.


It isn't, and AFAIK never was.

I was implying that all inline functions have internal linkage, ie. as if
they have "static" before them. They should all be defined in header files
if they're to be used in more than one translation unit.

-JKop
Jul 22 '05 #13
* JKop:
* Alf P. Steinbach posted:
* Richard Hayden:
* JKop wrote:
> inline
>
> is an abbreviation of:
>
> static inline

Really? I didn't think this was the case anymore.


It isn't, and AFAIK never was.


I was implying that all inline functions have internal linkage, ie. as if
they have "static" before them.


That is not correct.

In particular, the address of an inline function with external linkage
(the default) is the same in all translation units.

RTFM.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #14
Alf P. Steinbach posted:
That is not correct.

In particular, the address of an inline function with external linkage
(the default) is the same in all translation units.

RTFM.

An inline function doesn't have an address. Here's how inline functions
work.
inline void Poo(int& k)
{
k = 4;
}

int main()
{
int p = 7;

Poo(p);
}
This becomes:
int main()
{
int p = 7;

p = 4;
}

So pretty please could you explain to me how in the hell an inline function
could have an address in memory? I'm all ears.
-JKop
Jul 22 '05 #15
* JKop:

An inline function doesn't have an address.


RTFM §7.1.2/4.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #16
Richard Hayden wrote:
...
I understand what you mean in that case, so I have amended my code to:

/*******************test1.c*******************/
#include <iostream>

extern void dummy();

inline int testfunc() {
return 1;
}

int main(int argc, char** argv) {
std::cout << testfunc();
dummy();

return 0;
}
/*********************************************/

/*******************test2.c*******************/
#include <iostream>

extern int testfunc();

void dummy() {
std::cout << testfunc();
}
/*********************************************/

Surprisingly, it works as expected, i.e. the output is 11. How is this
occuring? Surely the linker must be doing some of the compiler's work
here in order to inline testfunc in the call in test2.c?
...


What you do here is basically a hack. Since inline functions have
external linkage by default (just like any other function) the compiler
has to take certain steps to ensure that expression
'&function_name_here' evaluates to the same value in every translation
unit where it is used. In typical implementation the burden of
satisfying this requirement is placed on the linker. For this reason,
the compiler has to include inline functions into linker tables, just
like non-inline functions. In your code sample above you exploited the
fact that inline function is present in the linker tables by trying to
link to that function from another translation unit. It is illegal from
the language specification point of view (Alf has already explained why)
but it might work in practice (as a hack). In my opinion,
implementations should use different name mangling formats for inline
functions to prevent such code from compiling.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #17
JKop wrote:
...
So pretty please could you explain to me how in the hell an inline function
could have an address in memory? I'm all ears.
...


Firstly, the bottom line is that at the language level any function has
address in memory.

Secondly, you are mixing two different and completely independent
things. One thing as "an inline/non-inline function". Another thing is
"an inlined/non-inlined call to a function". Nothing prevents the
compiler from generating a "regular" (non-inline) body for the function
(so that it has an address) and at the same time inline it whenever
possible. Remember also that the decision to inline a function can be
made on per-call basis, not on per-function basis. I.e. some calls to an
inline functions might get inlined, while other calls to the same
function might get directed to a "regular" body of that function.

Thirdly, nothing prevents the compiler from treating inline functions as
non-inline ones _and_ _vice_ _versa_. I.e. nothing prevents the compiler
from inlining non-inline functions. Formally speaking, at the language
level specifier 'inline' doesn't mean _anything_ besides that exception
from ODR specific to inline functions ("must be defined in every
translation unit..." etc.). The rest is up to the implementation.

--
Best regards,
Andrey Tarasevich

P.S. I bet you don't understand what sense does declaring a member
function as "virtual inline" make. Try googling for it, it's been beaten
do death.

Jul 22 '05 #18

"JKop" <NU**@NULL.NULL> wrote in message
news:gc*****************@news.indigo.ie...
Andrey Tarasevich posted:
JKop wrote:
inline

is an abbreviation of:

static inline
...


No.


You're educated. I wish I could make statements and provide support just
like you.


Well, you can, and you did! :-) You made an incorrect statement, and
provided nothing to back it up. (See Alf's posts for the actual facts of
the case.)

-Howard

Jul 22 '05 #19

Okay, I'm trying to get my head around this. Consider the following header
file, "yum.hpp":

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif
Now, consider that this function is called... inlinedly... in every instance
that it's called throughout the entire program, like so:

A.cpp

#include "yum.hpp"

int blah(void)
{
return Yum('s');
}
B.cpp

#include "yum.hpp"

int poo(char* n)
{
return Yum(*n);
}
So there's no problem at all with that.

But consider that there's just 3 instances in the program where it's
called... outlinedly. Each of these three callings are from 3 different
source files, 3 different translation units. The "problem" here is that this
fully-fledged function will be in memory not once, twice, but thrice. 3
copies of it in memory - that's a waste. If I were to specify external
linkage (and how would I?) for this function, then the linker would start
complaining because I'd have a multiple definition for each of the
translation units that include my "yum.hpp".
So here's my question: How to you get the function to be inline... yet...
where there's instances where it's called outlinedly, that there's only one
copy of it in memory, as opposed to 3.
Any explanations apprecitated.

(Just for more substance, the 3 instances where it's called outlinedly is
where something wants a pointer to a function).
-JKop
Jul 22 '05 #20
* JKop:

Okay, I'm trying to get my head around this. Consider the following header
file, "yum.hpp":

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif
Now, consider that this function is called... inlinedly... in every instance
that it's called throughout the entire program, like so:

A.cpp

#include "yum.hpp"

int blah(void)
{
return Yum('s');
}
B.cpp

#include "yum.hpp"

int poo(char* n)
{
return Yum(*n);
}
So there's no problem at all with that.

But consider that there's just 3 instances in the program where it's
called... outlinedly. Each of these three callings are from 3 different
source files, 3 different translation units. The "problem" here is that this
fully-fledged function will be in memory not once, twice, but thrice. 3
copies of it in memory - that's a waste.
Apart from the inlined calls a reasonable implementation will only have
one copy of the function in memory, since the function address is
required to be the same in all translation units.

If I were to specify external linkage (and how would I?)
By not using the word 'static'.

for this function, then the linker would start
complaining because I'd have a multiple definition for each of the
translation units that include my "yum.hpp".
No, that's exactly the what the word 'inline' _guarantees_ you won't
get (whether the function should additionally be inlined or not is up
to the compiler+linker, that aspect is not guaranteed in any way).
So here's my question: How to you get the function to be inline... yet...
where there's instances where it's called outlinedly, that there's only one
copy of it in memory, as opposed to 3.


No special action needed, that's what you get by default with any
reasonable implementation.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #21
JKop wrote:
Okay, I'm trying to get my head around this. Consider the following header
file, "yum.hpp":

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif

Now, consider that this function is called... inlinedly... in every instance
that it's called throughout the entire program, like so:

A.cpp

#include "yum.hpp"

int blah(void)
{
return Yum('s');
}
B.cpp

#include "yum.hpp"

int poo(char* n)
{
return Yum(*n);
}

So there's no problem at all with that.
Excellent.
But consider that there's just 3 instances in the program where it's
called... outlinedly. Each of these three callings are from 3 different
source files, 3 different translation units. The "problem" here is that this
fully-fledged function will be in memory not once, twice, but thrice. 3
copies of it in memory - that's a waste. If I were to specify external
linkage (and how would I?) for this function, then the linker would start
complaining because I'd have a multiple definition for each of the
translation units that include my "yum.hpp".
Firstly, at the language level there's no way to detect how many copies
of fully-fledged function body you have in your code (until you start
comparing addresses of this functions in different translation units).
This means that implementation is allowed to keep several copies if it
decides to do so. I don't think it could be referred to as a "waste"
since you yourself declared this function as 'inline', i.e. you yourself
requested the compiler to substitute _a_ _copy_ of function code in
every place where it is called. If you think about it, this is pretty
much the same kind of "waste" as having several copies of fully-fledged
function body.

Secondly, in order to ensure that the function has the same address in
all translation units, the implementation should be able to recognize
the situations where the address of an inline function is taken and
"synchronize" their results between translation units, i.e. all pointers
to inline function should actually point to the same fully-fledged
function body. This is typically ensured by the linker. In the end, only
one copy of fully-fledged function body is really used in the program.
All other copies are not be used and can be safely discarded. This is
also done by the linker.

Thirdly, it is responsibility of the implementation to make sure that
there are no diagnostic messages (from the linker or anywhere else)
triggered by multiple copies of fully-fledged function body. There are
different ways to achieve that and I don't really understand why you
even care about it.
So here's my question: How to you get the function to be inline... yet...
where there's instances where it's called outlinedly, that there's only one
copy of it in memory, as opposed to 3.


In short, you follow these steps:

1. Generate three copies in memory (done by the compiler)
2. Make sure only one copy is actually used by redirecting all
references to a single copy (done by the linker)
3. Discard unused copies (done by the linker)

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #22
JKop posted:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif

Just to play devil's advocate here, I'm gonna rewrite that:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif
I want to make sure that ALL of the calls to this function, whether inline
or outline, all refer to the same static variable!
-JKop
Jul 22 '05 #23
JKop wrote:

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif
I want to make sure that ALL of the calls to this function, whether inline
or outline, all refer to the same static variable!
...


This simply means that the linker will have to merge all instances if
that 'counter' variable from different translation units into one. Just
like it merges all full-fledged bodies for the same inline function into
one (see my previous message).

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #24
On Tue, 29 Jun 2004 21:45:33 GMT, JKop <NU**@NULL.NULL> wrote:
JKop posted:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif

Just to play devil's advocate here, I'm gonna rewrite that:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif
I want to make sure that ALL of the calls to this function, whether inline
or outline, all refer to the same static variable!
-JKop


The inline directive does not *require* the compiler to actually copy
the function implementation anywhere, it is only a hint.

If the compiler "thinks" the function cannot (or should not) be
inlined, it won't do it.

--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #25
Andrey Tarasevich posted:
JKop wrote:

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;

return ++counter - 5; }

#endif
I want to make sure that ALL of the calls to this function, whether
inline or outline, all refer to the same static variable!
...


This simply means that the linker will have to merge all instances if
that 'counter' variable from different translation units into one. Just
like it merges all full-fledged bodies for the same inline function
into one (see my previous message).

But I never asked it to do that.

I could just as easily want it to *not* do that.

As long as the inline function is in a header file, there will be multiple
instances of it for each seperate translation unit. That is, for each
translation unit into which it's included, there should be separate static
variables. That is, an inline function should be treated as if it is "static
inline". Inline functions have internal linkage - I believe someone-one
suggested that they don't.

It would be nice to just stick an inline function into a source file and
give it good old fashioned external linkage. One could argue that it can't
be expanded inlinedly into other translation units... but why can't the
compiler and linker collaborate and make it so?, ie.

Yum.cpp

inline int Yum(char k)
{
static unsigned char counter = 3;

return ++counter - 5;
}
and then

Crocodile.cpp

int main()
{
char j = 's';

Yum(j);
}
and still for it to be expanded inline in main() !
Does anyone disagree with me that "inline" == "static inline". If so, please
supply arguments.
I think it would be good if you could specify inline when you're *calling* a
function, even when the function's *defined* outline, and yet for it to
still use the same static variables - Consider a loop that loops
1,354,353,364,747,466,574 times. You'd want the functions called from within
it to be inlined, even if they are not defined with the "inline" keyword.
Out of that, I fantasize the following amendments to C++, specifically, the
addition of the following keywords:

For calling the function:

call_inline : calls the function inline, regardless of whether it's defined
with "inline"

call_outline : calls the function outline, regardless of whether it's
defined with "inline"

If you don't specify one of the above keywords, then you're implicitly
specifying the keyword:

call_according_to_definition : calls the function inline if it's defined
inline. Calls the function outline if it's not declared inline.
For defining the function:

inline : if the function is called with call_according_to_definition then
it's called inline.

outline : this will be an implicit keyword that's specified when you *don't*
define the function as inline. If the function is called with
call_according_to_definition, then it's called outline.

Here's a quick example:
double Cow(double pig)
{
return pig / 7 * 4 + 6 - 22 / 4;
}
int main()
{
unsigned long int amount_times = -1; //Max value (BTW, if have we come
to a decision yet on whether this is non-undefined behaviour?)

double r = 22.0;

for (unsigned long int counter = 0; counter < amount_times ; ++counter)
{
r = call_inline Cow(r); //Maybe some sort of angle brackets or
parenthesis or maybe even square brackets there
}
}
END OF FANTASY
-JKop
Jul 22 '05 #26
Bob Hairgrove posted:
The inline directive does not *require* the compiler to actually copy
the function implementation anywhere, it is only a hint.

If the compiler "thinks" the function cannot (or should not) be
inlined, it won't do it.

We've moved past that. We're talking about internal linkage Vs. external
linkage now. That is, for internal linkage, there'll be multiple instances
of the function and they'll all have *unique* static varibles; and for
external linkage, they'll be but one instance of the function and *all*
calls to it will work with the same static variables.
-JKop
Jul 22 '05 #27
JKop wrote:
JKop wrote:

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;

return ++counter - 5; }

#endif
I want to make sure that ALL of the calls to this function, whether
inline or outline, all refer to the same static variable!
...
This simply means that the linker will have to merge all instances if
that 'counter' variable from different translation units into one. Just
like it merges all full-fledged bodies for the same inline function
into one (see my previous message).

But I never asked it to do that.


According to the language specification that's what is done _by_ _default_.
I could just as easily want it to *not* do that.
If you don't like it you have to specifically ask the implementation not
to do that. Place your inline function into header file but explicitly
declare it as 'static', for example. That way you'll get separate
'counter' in every translation unit.
As long as the inline function is in a header file, there will be multiple
instances of it for each seperate translation unit. That is, for each
translation unit into which it's included, there should be separate static
variables.
Conceptually - no. That would contradict the language specification.
Practically - that's exactly how it is at compilation stage. But later
the linker takes care of these separate variables merging them into one.
That is, an inline function should be treated as if it is "static
inline". Inline functions have internal linkage - I believe someone-one
suggested that they don't.
Inline functions have external linkage by default, just like non-inline
functions. If you want an inline function to have internal linkage, you
have to declare it as 'static'.
It would be nice to just stick an inline function into a source file and
give it good old fashioned external linkage. One could argue that it can't
be expanded inlinedly into other translation units... but why can't the
compiler and linker collaborate and make it so?, ie.

Yum.cpp

inline int Yum(char k)
{
static unsigned char counter = 3;

return ++counter - 5;
}
and then

Crocodile.cpp

int main()
{
char j = 's';

Yum(j);
}
and still for it to be expanded inline in main() !
Well, that probably didn't agree with the generally accepted idea of
what a "linker" is and what it can do. For this reason, the standard
decided to use different approach.
Does anyone disagree with me that "inline" == "static inline". If so, please
supply arguments.


According to the language standard, functions in C++ have external
linkage by default. The standard makes no exceptions from this rule for
inline functions.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #28
JKop <NU**@NULL.NULL> wrote in news:1q*****************@news.indigo.ie:
JKop posted:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
return k - 5;
}

#endif

Just to play devil's advocate here, I'm gonna rewrite that:
#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif
I want to make sure that ALL of the calls to this function, whether
inline or outline, all refer to the same static variable!


Done. The Standard states that in section 7.1.2(4).
Jul 22 '05 #29
JKop <NU**@NULL.NULL> wrote in news:W5*****************@news.indigo.ie:
Here's a quick example:
double Cow(double pig)
{
return pig / 7 * 4 + 6 - 22 / 4;
}
int main()
{
unsigned long int amount_times = -1; //Max value (BTW, if
have we come
to a decision yet on whether this is non-undefined behaviour?)

double r = 22.0;

for (unsigned long int counter = 0; counter < amount_times ;
++counter) {
r = call_inline Cow(r); //Maybe some sort of angle
brackets or
parenthesis or maybe even square brackets there
}
}
END OF FANTASY


Simply declare Cow as inline, and let the optimizer deal with it. It's
generally smarter than you are about these things.
Jul 22 '05 #30
Andre Kostur posted:
JKop <NU**@NULL.NULL> wrote in news:W5*****************@news.indigo.ie:
Here's a quick example:
double Cow(double pig)
{
return pig / 7 * 4 + 6 - 22 / 4; }
int main()
{
unsigned long int amount_times = -1; //Max value (BTW, if
have we come
to a decision yet on whether this is non-undefined behaviour?)

double r = 22.0;

for (unsigned long int counter = 0; counter < amount_times ;
++counter) {
r = call_inline Cow(r); //Maybe some sort of angle
brackets or
parenthesis or maybe even square brackets there } }
END OF FANTASY


Simply declare Cow as inline, and let the optimizer deal with it. It's
generally smarter than you are about these things.


Consider that Cow is reusable code, maybe even within a library, so you
don't want to go messing with it.

-JKop
Jul 22 '05 #31
Andre Kostur posted:
I want to make sure that ALL of the calls to this function, whether
inline or outline, all refer to the same static variable!


Done. The Standard states that in section 7.1.2(4).

Here's something that's got me... concerned.
I wrote this little project:
Yum.hpp
-------

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif

Yummy.hpp
---------

#ifndef INCLUDE_YUMMY_HPP
#define INCLUDE_YUMMY_HPP

inline int Yum(char k)
{
static unsigned char counter = 27;

counter *= 2;

return counter++ - 2;
}

#endif
ape.cpp
-------

#include "yummy.hpp"

unsigned int ape()
{
char rent = 'r';

Yum(rent);
}

cow.cpp
-------

extern int Yum(char); //Testing external linkage

unsigned int cow()
{
return Yum('p') - 23;
}

main.cpp
--------

#include <iostream>

#include "yum.hpp"

extern unsigned int cow();

extern unsigned int ape();
int main()
{
std::cout << Yum('r')
<< ape()
<< cow();

}

----

g++ -c main.cpp ape.cpp cow.cpp

g++ -o chello main.o ape.o cow.o

chello.exe outputs:

104294967272

----
A) cow.cpp compiles. Therefore there's a Yum function that has external
linkage. Which Yum is it calling? There's two different Yum functions. Two
different functions with the same name... Multiple Definition I would hope.
But NO!

C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't. When a
certain translation unit calls the function Yum, which Yum is it calling?
AHH!

Seems like one big mess to me: Giving inline functions external linkage and
actually allowing multiple definitions is a recipe for disaster.
-JKop
Jul 22 '05 #32

Putting outputs in each function, I get:

Entered main
Entered Yum from Yum.hpp
-1
Entered ape
Entered Yum from Yum.hpp
0
Entered cow
Entered Yum from Yum.hpp
4294967274
For no particular reason, the Yum in Yummy.hpp is being ignored.
-JKop
Jul 22 '05 #33
JKop <NU**@NULL.NULL> wrote in news:Tz*****************@news.indigo.ie:
Andre Kostur posted:
I want to make sure that ALL of the calls to this function, whether
inline or outline, all refer to the same static variable!
Done. The Standard states that in section 7.1.2(4).

Here's something that's got me... concerned.
I wrote this little project:
Yum.hpp
-------

#ifndef INCLUDE_YUM_HPP
#define INCLUDE_YUM_HPP

inline int Yum(char k)
{
static unsigned char counter = 3;
return ++counter - 5;
}

#endif

Yummy.hpp
---------

#ifndef INCLUDE_YUMMY_HPP
#define INCLUDE_YUMMY_HPP

inline int Yum(char k)
{
static unsigned char counter = 27;

counter *= 2;

return counter++ - 2;
}

#endif
ape.cpp
-------

#include "yummy.hpp"

unsigned int ape()
{
char rent = 'r';

Yum(rent);
}

cow.cpp
-------

extern int Yum(char); //Testing external linkage

unsigned int cow()
{
return Yum('p') - 23;
}

main.cpp
--------

#include <iostream>

#include "yum.hpp"

extern unsigned int cow();

extern unsigned int ape();
int main()
{
std::cout << Yum('r')
<< ape()
<< cow();

}

----

g++ -c main.cpp ape.cpp cow.cpp

g++ -o chello main.o ape.o cow.o

chello.exe outputs:

104294967272

----
A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage. Which Yum is it calling? There's two different Yum
functions. Two different functions with the same name... Multiple
Definition I would hope. But NO!


Not when Cow is compiled. There is only on amorphous Yum(char) function
floating around somewhere, to be resolved at link time.
Where's B) ? :)
C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't.
When a certain translation unit calls the function Yum, which Yum is
it calling? AHH!
You're probably triggering a clause somewhere that when the linker sees
two instances of an inlined Yum(char) funtion, it's allowed to assume
that they're the same and can drop one of them. Remove the inline
qualifiers and see what happens.
Seems like one big mess to me: Giving inline functions external
linkage and actually allowing multiple definitions is a recipe for
disaster.


Seems like a mess that you've self-inflicted. First thing I'd do, is
forget using your "extern" statements, and use the appropriate header
files.
Jul 22 '05 #34
Andre Kostur posted:

A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage. Which Yum is it calling? There's two different Yum
functions. Two different functions with the same name... Multiple
Definition I would hope. But NO!


Not when Cow is compiled. There is only on amorphous Yum(char) function
floating around somewhere, to be resolved at link time.


When Cow is compiled, no Yum exists AT ALL. All it has is an extern
statement.

At link time however, the translation unit formed from main.cpp will contain
an inline Yum function, just as the translation unit formed from ape.cpp
will contain and inline Yum function - two unique functions with external
linkage.

C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't.
When a certain translation unit calls the function Yum, which Yum is
it calling? AHH!


You're probably triggering a clause somewhere that when the linker sees
two instances of an inlined Yum(char) funtion, it's allowed to assume
that they're the same and can drop one of them. Remove the inline
qualifiers and see what happens.

I think this is bullshit. An inline function should be just like any other
function, ie. if it's defined twice, then the compiler doesn't flip a coin,
it spits out "RED ALERT! MULTIPLE DEFINITION!". The whole idea of namespaces
arose from this attitude.

From now on I'm sticking "static" in front of every inline function I write.
If two translation units call this function outline, or want an address to
it, I'll use global pointer variables.

Allowing multiple definitions is a farse.

Seems like one big mess to me: Giving inline functions external
linkage and actually allowing multiple definitions is a recipe for
disaster.


Seems like a mess that you've self-inflicted. First thing I'd do, is
forget using your "extern" statements, and use the appropriate header
files.


I used the "extern" statements for clarity.

Which header files am I using that are inappropriate?
-JKop
Jul 22 '05 #35
JKop wrote:
...
A) cow.cpp compiles. Therefore there's a Yum function that has external
linkage.
Wrong conclusion. The program is invalid, the behavior is undefined. It
can compile, but that means nothing. Moreover, it is possible to create
a conforming implementation that will not compile this program. The one
that you are using is simply too lazy to detect this type of error.
Which Yum is it calling? There's two different Yum functions. Two
different functions with the same name... Multiple Definition I would hope.
But NO!
The behavior is undefined. Maybe it is not calling any 'Yum's at all.
C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't. When a
certain translation unit calls the function Yum, which Yum is it calling?
AHH!
One again, you have wrong idea about what "external linkage" is.
"External linkage" doesn't guarantee that function can be _called_ from
another translation unit. "External linkage" means that function can be
_referred_ from another translation units. What concrete ways of
"referring" are hiding behind this generic term depends on several other
factors. In your particular case "calling" function 'Yum' from 'cow.cpp'
is not a legal way to "refer" to it. The fact that program "compiles"
means nothing (I'm actually surprised that you use the "compilability"
of the program as some kind of proof of it validity.)
Seems like one big mess to me: Giving inline functions external linkage and
actually allowing multiple definitions is a recipe for disaster.


Trying to exploit the compiler's "security hole", which allows "linking"
to 'inline' functions from another translation unit, is a recipe for
disaster. Just don't do it.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #36
Andrey Tarasevich posted:
JKop wrote:
...
A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage.
Wrong conclusion. The program is invalid, the behavior is undefined.


I disagree.

Chapter and verse, please.
It can compile, but that means nothing. Moreover, it is possible to
create a conforming implementation that will not compile this program.
The one that you are using is simply too lazy to detect this type of
error.


Try to keep up here:

You have a translation unit. From within it, a function called "Yum" is
called. This "Yum" function is not in the current translation unit.
Therefore, granted that the project successfully compiles and links, "Yum"
must be in a different translation unit.

In agreement so far?

If this "Yum" function in translation unit A is visible from, can be called
from, can be referred to from; all from within translation unit B, then what
you've got there is the miracle of "external linkage".

Which Yum is it calling? There's two different Yum functions. Two
different functions with the same name... Multiple Definition I would
hope. But NO!


The behavior is undefined. Maybe it is not calling any 'Yum's at all.

Chapter and Verse again, please.

C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't.
When a certain translation unit calls the function Yum, which Yum is
it calling? AHH!


One again, you have wrong idea about what "external linkage" is.
"External linkage" doesn't guarantee that function can be _called_ from
another translation unit. "External linkage" means that function can be
_referred_ from another translation units. What concrete ways of
"referring" are hiding behind this generic term depends on several
other factors. In your particular case "calling" function 'Yum' from
'cow.cpp' is not a legal way to "refer" to it. The fact that program
"compiles" means nothing (I'm actually surprised that you use the
"compilability" of the program as some kind of proof of it validity.)


That entire paragraph reads like bullshit to me. If a certain function in a
certain translation unit has external linkage, then you can do whatever the
hell you want to it from another translation unit - call it, refer to it,
takes it address, feed it ice-cream...

Seems like one big mess to me: Giving inline functions external
linkage and actually allowing multiple definitions is a recipe for
disaster.


Trying to exploit the compiler's "security hole", which allows
"linking" to 'inline' functions from another translation unit, is a
recipe for disaster. Just don't do it.

The alleged security hole is in the C++ Standard, which allows multiple
definition of a function. Here's some deductive reasoning for you:

A) A function with a certain name and a certain list of arguments can be
defined but once. Any subsequent definitions of the aformentioned function
yield a "Multiple Definition" compile error.

B) An inline function *IS* a function, concordantly it abides to A above.
This is where the Standard begins to choke on its own puke, as I have
demonstrated with my sample project.
My conclusions:

Solution One: All inline functions be defined in header files and be
prefixed with "static inline".

Solution Two: All inline functions are defined in a CPP file with external
linkage. The compiler and linker, collaborating as a complinker, make inline
calls inline and outline calls outline.
-JKop
Jul 22 '05 #37
JKop <NU**@NULL.NULL> wrote in news:fw*****************@news.indigo.ie:
Andrey Tarasevich posted:
JKop wrote:
...
A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage.
Wrong conclusion. The program is invalid, the behavior is undefined.


I disagree.

Chapter and verse, please.


Section 3.2
It can compile, but that means nothing. Moreover, it is possible to
create a conforming implementation that will not compile this
program. The one that you are using is simply too lazy to detect this
type of error.


Try to keep up here:

You have a translation unit. From within it, a function called "Yum"
is called. This "Yum" function is not in the current translation unit.
Therefore, granted that the project successfully compiles and links,
"Yum" must be in a different translation unit.


Unfortunately since you've invoked undefined behaviour, who knows what
happens.
Which Yum is it calling? There's two different Yum functions. Two
different functions with the same name... Multiple Definition I
would hope. But NO!


The behavior is undefined. Maybe it is not calling any 'Yum's at all.

Chapter and Verse again, please.


Same chapter. 3.2
Seems like one big mess to me: Giving inline functions external
linkage and actually allowing multiple definitions is a recipe for
disaster.


Trying to exploit the compiler's "security hole", which allows
"linking" to 'inline' functions from another translation unit, is a
recipe for disaster. Just don't do it.

The alleged security hole is in the C++ Standard, which allows
multiple definition of a function. Here's some deductive reasoning for
you:

A) A function with a certain name and a certain list of arguments can
be defined but once. Any subsequent definitions of the aformentioned
function yield a "Multiple Definition" compile error.


Proceeding from a false premise. The compiler isn't required to issue a
diagnostic.
B) An inline function *IS* a function, concordantly it abides to A
above. This is where the Standard begins to choke on its own puke, as
I have demonstrated with my sample project.


Nope, you've violated the One Definition Rule. See section 3.2. Most
important is the last line:

"If the definitions of D do not satisfy these requirements, then the
behaviour is undefined."

Next question... are you seriously attempting to learn C++? Or are you
trying to do something else?

Jul 22 '05 #38

But didn't some-one say that inline functions are allowed a multiple
definition?
Is a C++ Standard compliant compiler allowed to compile whatever it likes?
For instance can it compile the following without giving any errors at all?:
#include <int main()
{
#include <iostream> chocolate;

++chocolate++ = 54;

return inline; ? 6 :? cout << "Hello World";>
If so, then yes, my sample code does in fact have a Multiple Definition.
Deductive Reasoning:

1) Multiple Definitions are Undefined Behaviour.

2) My code contains Multiple Definitions.

3) My code contains Undefined Behaviour.
What I would absolutely love an explanation to is this, why does the
following not compile:
int Yum(char)
{
std::cout << "monkey!";

return 't';
}

int Yum(char)
{
std::cout << "ape!";

return 'k';
}
while the following does:
inline int Yum(char)
{
std::cout << "monkey!";

return 't';
}

inline int Yum(char)
{
std::cout << "ape!";

return 'k';
}
Is it:

A) Because Standard C++ allows multiple definitions of inline functions. If
so, then my code is *not* undefined behaviour, as there's nothing undefined
about multiple defining an inline function.

B) Because g++ is shit?
-JKop
Jul 22 '05 #39
JKop wrote:
...
A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage.
Wrong conclusion. The program is invalid, the behavior is undefined.


I disagree.

Chapter and verse, please.


"Chapter and verse" was named here on numerous occasions. However, you
chose to ignore it. How is this time different? Anyway, 7.1.2/2 clearly
states that an inline function with external linkage must be declared
'inline' in every translation unit in which it appears. It also says
that it shall be _defined_ in every translation unit in which it is
used. The standard says nothing about the behavior in situations when
the above requirements are violated. This is undefined behavior, by
definition of 'undefined behavior' given in 1.3.12.
It can compile, but that means nothing. Moreover, it is possible to
create a conforming implementation that will not compile this program.
The one that you are using is simply too lazy to detect this type of
error.


Try to keep up here:

You have a translation unit. From within it, a function called "Yum" is
called. This "Yum" function is not in the current translation unit.
Therefore, granted that the project successfully compiles and links, "Yum"
must be in a different translation unit.

In agreement so far?


No. The program is invalid. If some implementation manages to compile
it, it simply means that in one way or another it implements some
"default solution" for this situation. It could be just anything. It
might call some default "stub" function created specifically for this
type of situation. It might do something else. Strictly speaking, the
behavior that you observe in your experiment is not much different from
that.

Also, once again, the fact that certain implementation compiles it means
absolutely nothing. Some other implementation (including the next
version of this one) might refuse to compile it.
If this "Yum" function in translation unit A is visible from, can be called
from, can be referred to from; all from within translation unit B, then what
you've got there is the miracle of "external linkage".
No. It is nothing more than "successful" attempt to exploit the
aforementioned "security hole". Yes, this hole is there because of
"external linkage". But it could have been implemented in much safer
manner. The implementation that you are using decided to implement it in
unsafe manner. It is nothing more than a quality-of-implementation issue.
Which Yum is it calling? There's two different Yum functions. Two
different functions with the same name... Multiple Definition I would
hope. But NO!


The behavior is undefined. Maybe it is not calling any 'Yum's at all.


Chapter and Verse again, please.


Above.
C) The two inline functions both have external linkage, but they are
DIFFERENT. I'd like to get a multiple definition error, but I amn't.
When a certain translation unit calls the function Yum, which Yum is
it calling? AHH!


One again, you have wrong idea about what "external linkage" is.
"External linkage" doesn't guarantee that function can be _called_ from
another translation unit. "External linkage" means that function can be
_referred_ from another translation units. What concrete ways of
"referring" are hiding behind this generic term depends on several
other factors. In your particular case "calling" function 'Yum' from
'cow.cpp' is not a legal way to "refer" to it. The fact that program
"compiles" means nothing (I'm actually surprised that you use the
"compilability" of the program as some kind of proof of it validity.)


That entire paragraph reads like bullshit to me. If a certain function in a
certain translation unit has external linkage, then you can do whatever the
hell you want to it from another translation unit - call it, refer to it,
takes it address, feed it ice-cream...


Well, you seem to throw the word "bullshit" around a lot these days.
And, may I notice, you've embarrassed yourself more than a few times
with it. I recommend you to get better understanding of C++ terminology
and forget about those frivolous interpretations of C++ terms you seem
to assume all the time. There's no point to continue this discussion
until you take care of this problem or at least acknowledge its existence.
Seems like one big mess to me: Giving inline functions external
linkage and actually allowing multiple definitions is a recipe for
disaster.
Trying to exploit the compiler's "security hole", which allows
"linking" to 'inline' functions from another translation unit, is a
recipe for disaster. Just don't do it.

The alleged security hole is in the C++ Standard, which allows multiple
definition of a function.


There's no security hole in the standard. The standard simply throws
this into the "undefined behavior" pile. The rest is a
quality-of-implementation issue.

Here's some deductive reasoning for you:
A) A function with a certain name and a certain list of arguments can be
defined but once. Any subsequent definitions of the aformentioned function
yield a "Multiple Definition" compile error.

B) An inline function *IS* a function, concordantly it abides to A above.
This is where the Standard begins to choke on its own puke, as I have
demonstrated with my sample project.
Not true. ODR consists of several sub-rules, directed at different
entities in the language. Sub-rule for inline functions is quite
different for sub-rule for ordinary functions. As far as ODR is
concerned, ordinary functions and inline functions are different beasts,
even though they both are called "functions".

What you do here is rather primitive demagogy. You substitute the
meanings of standard terms with something of your own concoction. And
then you try to see what will happen to certain portions of the document
if you interpret it within that new terminology of yours. The result
doesn't make any sense (not surprisingly). And now you call it "the
standard's own puke"? LOL
My conclusions:

Solution One: All inline functions be defined in header files and be
prefixed with "static inline".
Whatever.
Solution Two: All inline functions are defined in a CPP file with external
linkage. The compiler and linker, collaborating as a complinker, make inline
calls inline and outline calls outline.


Not C++.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #40
Andrey Tarasevich posted:
JKop wrote:
...
A) cow.cpp compiles. Therefore there's a Yum function that has
external linkage.

Wrong conclusion. The program is invalid, the behavior is undefined.


I disagree.

Chapter and verse, please.


"Chapter and verse" was named here on numerous occasions. However, you
chose to ignore it. How is this time different? Anyway, 7.1.2/2 clearly
states that an inline function with external linkage must be declared
'inline' in every translation unit in which it appears. It also says
that it shall be _defined_ in every translation unit in which it is
used. The standard says nothing about the behavior in situations when
the above requirements are violated. This is undefined behavior, by
definition of 'undefined behavior' given in 1.3.12.


Take out cow.cpp and omit the function call to "cow" from main, and then I
no longer violate the above. But that still doesn't clarify whether ape()
calls Yum from yum.hpp or yummy.hpp.

If an inline function shall be defined in every translation unit in which it
is used, then why does it have external linkage?
-JKop
Jul 22 '05 #41
JKop <NU**@NULL.NULL> wrote in news:2k*****************@news.indigo.ie:

But didn't some-one say that inline functions are allowed a multiple
definition?
Read section 3.2(5) of the Standard. Of particular interest is that
"inline function with external linkage" is permitted to have multiple
definitions, with certain restrictions, the most important in this case
is "each definition of D shall consist of the same sequence of tokens".

Your example violates that condition, thus you have undefined behaviour.
Is a C++ Standard compliant compiler allowed to compile whatever it
likes? For instance can it compile the following without giving any
errors at all?:
Not quite. There are certain things that require diagnostics and some
that don't.
#include <int main()
{
#include <iostream> chocolate;

++chocolate++ = 54;

return inline; ? 6 :? cout << "Hello World";>
I'd get a different compiler if it did that without a diagnostic.. but
that's a Quality of Implementation issue, not a Standard issue.
If so, then yes, my sample code does in fact have a Multiple
Definition. Deductive Reasoning:

1) Multiple Definitions are Undefined Behaviour.
Imprecise definitions. Depends on what you mean by "Multiple
Definitions". If you have the _same_ sequence of tokens for an inline
with external linkage in two different translation units, is that a
"Multiple Definition"? If so, then this premise is not universally true.
2) My code contains Multiple Definitions.
Yes
3) My code contains Undefined Behaviour.
Yes
What I would absolutely love an explanation to is this, why does the
following not compile:
int Yum(char)
{
std::cout << "monkey!";

return 't';
}

int Yum(char)
{
std::cout << "ape!";

return 'k';
}
Those two are simply functions (which falls under Section 3.2(3))
while the following does:
inline int Yum(char)
{
std::cout << "monkey!";

return 't';
}

inline int Yum(char)
{
std::cout << "ape!";

return 'k';
}
These are inline functions with external linkage (which falls under
Section 3.2(5)).
Is it:

A) Because Standard C++ allows multiple definitions of inline
functions. If so, then my code is *not* undefined behaviour, as
there's nothing undefined about multiple defining an inline function.
Depending on your definition of "multiple definitions". Multple places
where you specify the body of the function? Yep it's allowed. As long
as the two bodies are the same sequence of tokens.
B) Because g++ is shit?


You seem to be fixated on something.....
Jul 22 '05 #42

"Andre Kostur" <nn******@kostur.net> wrote in message
... As long
as the two bodies are the same sequence of tokens.


What does that mean, exactly? That the function definitions (bodies) must
be identical (after ignoring white space)? If that's what you're saying,
then I'm confused, because the bodies of those two functions were different.
(One output "monkey" and returned 't', while the other output "ape" and
returned 'k'.)

-Howard
Jul 22 '05 #43
JKop wrote:

Wrong conclusion. The program is invalid, the behavior is undefined.

I disagree.

Chapter and verse, please.
"Chapter and verse" was named here on numerous occasions. However, you
chose to ignore it. How is this time different? Anyway, 7.1.2/2 clearly
states that an inline function with external linkage must be declared
'inline' in every translation unit in which it appears. It also says
that it shall be _defined_ in every translation unit in which it is
used. The standard says nothing about the behavior in situations when
the above requirements are violated. This is undefined behavior, by
definition of 'undefined behavior' given in 1.3.12.


Take out cow.cpp and omit the function call to "cow" from main, and then I
no longer violate the above. But that still doesn't clarify whether ape()
calls Yum from yum.hpp or yummy.hpp.


I didn't intend to re-type the standard word-to-word in my previous
message, so I omitted some things. (Why don't you just take the document
and read it yourself?). The important thing in this case is that inline
function shall be _defined_ in every translation unit in which it is
used and that it should be defined _identically_ in all those
translation units (see 7.1.2/4). If you get rid of 'cow.cpp', you'll
still have 'main.cpp' and 'ape.cpp' both of which contain a definition
of an inline function 'Yum' with external linkage and these definitions
are different from each other. That's a direct violation of requirements
stated in 7.1.2/4.
If an inline function shall be defined in every translation unit in which it
is used, then why does it have external linkage?


Why not? As I said several times before, apparently you understand
"having external linkage" as "being linkable through a simple extern
declaration from another translation unit". This is not a correct
understanding. The notion of "having external linkage" applies to a lot
of different entities in the language (types, for example, also have
linkage in C++) and means a lot of different things. Some of these
things are not applicable to inline functions, some are applicable. For
example, one thing that applies to inline functions is that an inline
function with external linkage is guaranteed to have the same address in
every translation unit (also remember that thing with local static
variables etc.). If you care about these guarantees, you should declare
your function with external linkage. Otherwise, declare it with internal
linkage if you wish.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #44
"Howard" <al*****@hotmail.com> wrote in
news:T1********************@bgtnsc04-news.ops.worldnet.att.net:

"Andre Kostur" <nn******@kostur.net> wrote in message
... As long
as the two bodies are the same sequence of tokens.


What does that mean, exactly? That the function definitions (bodies)
must be identical (after ignoring white space)? If that's what you're
saying, then I'm confused, because the bodies of those two functions
were different. (One output "monkey" and returned 't', while the other
output "ape" and returned 'k'.)


.... you'd have to read the Standard to get all the picky details, but my
understanding of it is that the two functions have to be basically
identical. If they're not, you've wandered over into Undefined Behaviour.
Which is why JKop's programs are "bad".
Jul 22 '05 #45
Andre Kostur posted:
Read section 3.2(5) of the Standard. Of particular interest is that
"inline function with external linkage" is permitted to have multiple
definitions, with certain restrictions, the most important in this case
is "each definition of D shall consist of the same sequence of tokens".


What in the name of whipped ice-cream, dipped in 100s 'n' 1,000s, oozed with
red syrup is "the same sequence of tokens"?

Does it mean the exact same code?
-JKop
Jul 22 '05 #46

The C++ Programming Language 3rd Edition by Bjarne Stroustrup page 199,
section 9.2:

An inline function must be defined - by identical definitions - in every
translation unit in which it is used. Consequently, the following example
isn't just bad taste; it is illegal:

// file1.c:
inline int f(int i) { return i; }

// file2.c:
inline int f(int i) { return i + 1; }

Unfortunately, this error is hard for an implementation to catch, and the
following - otherwise perfectly logical - combination of external linkage
and inlining is banned to make life simpler for compiler writers:
// file1.c
extern inline int g(int i);
int h(int i) { return g(i); } //error: g() undefined in this
translation unit

// file2.c
extern inline int g(int i) { return i + 1; }
By default, consts and typedefs have internal linkage. Consequently this
example is legal (although potentially confusing):
// file1.c
typedef int T;
const int x = 7;

// file2.c
typedef void T;
const int x = 8;
Global variables that are local to a single compilation unit are a common
source of confusion and are best avoided. To ensure consistency, you should
usually place global consts and inlines in header files only.
A const can be given external linkage by an explicit declaration:
// file1.c:
extern const int a = 77;

// file2.c:
extern const int a;

void g()
{
cout << a << '\n';
}
Here, g() will print 77.
-JKop
Jul 22 '05 #47
JKop wrote:
The C++ Programming Language 3rd Edition by Bjarne Stroustrup page 199,
section 9.2:
...


And? What exactly is the point?

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #48

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Tron Thomas | last post by:
I have read that anonymous namespaces are preferred in C++ over declaring global statics because the namespace can hide information from other translation units and at the same time provide...
9
by: maxw_cc | last post by:
Hi to all, To explain my question I'll help myself with the following two code snippets: /*** file1.c ***/ #include <stdio.h> void print_it(void);
19
by: J. J. Farrell | last post by:
After many years of dealing with definition and linkage issues in ways that I know to be safe, I've decided it's time to try to understand this area properly. Consider a header file with the file...
4
by: Peter Ammon | last post by:
I would like to share a variable between two functions defined in two separate source files; no other functions will need the global variable so I'd prefer to not give it file scope. Thus, I want...
3
by: al.cpwn | last post by:
do static and inline functions or members have internal linkage? I have been reading this newsgroup on google and found conflicting ideas. Can someone please help me understand why in some places...
1
by: Kurt | last post by:
The C++ standard (in 3.5:6, p42Example) said: static int i = 0; // 1 void g() { int i; //2: i has no linkage { extern int i; //3: external linkage
12
by: destination | last post by:
"If a declaration for an identifier within a block does not include the extern specifier, then the identifier has no linkage and is unique to the function. If it does include extern, and an external...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.