Scope of inline functions

O

Ondrej Spanel

I though that inline functions should be always visible only in the
compilation unit where they are defined - meaning if compiler cannot inline
them, they should be handled as if declared static. However sample attached
shows VC compiler does not work this way (tested in .NET 2003). When you
compile the sample with inlining enabled (like in default Release config),
the output is A1 = 1, A2 = 2. When run with inlining disabled (Debug),
output is A1 = 1, A2 = 1 - the compiler/linker uses the same version of the
A function in both compilation units, and it even gives no warning.

When I use "static inline" instead of "inline" for both A functions, it
works as expected. When I do not use any qualification (or use extern), the
linker gives error A is defined twice. My conclusion is current behaviour
with"inline" is both inconsistend and unsafe, as any compilation unit may
unknowningly use different inline function in case inline function is not
inlined (which is somethnig compiler is free to decide, and it is normal in
debug builds).

I recently experienced very similiar issue with global operator new - even
if it was inlined, it was shared accross various modules, leading to
unexpected behaviour. The issue was quite confusing, as I did not expect at
all other modules (in this case static libraries) could see my (inlined)
definition of operator new.

Regards
Ondrej

---------------------------------------
Ondrej Spanel
Lead Programmer
Bohemia Interactive Studio
www.bistudio.com
www.flashpoint1985.com


////////////////////////////////////////////////////////////////////////////
////////////
/// first.cpp
#include <stdio.h>
inline int A()
{
return 1;
}
int CallA2();

int CallA1()
{
return A();
}
int main(int argc, const char *argv[])
{
printf("A1 = %d\n",CallA1());
printf("A2 = %d\n",CallA2());
getchar();
return 0;
}
/// end of first.cpp

////////////////////////////////////////////////////////////////////////////
////////////
/// second.cpp
inline int A()
{
return 2;
}
int CallA2()
{
return A();
}
/// end of second.cpp
 
O

Ondrej Spanel

Can anyone please confirm if this is bug (seems like that to me), or is
there some problem in the code provided?

Regards
Ondrej
 
D

David Lowndes

Ondrej Spanel said:
I though that inline functions should be always visible only in the
compilation unit where they are defined - meaning if compiler cannot inline
them, they should be handled as if declared static. However sample attached
shows VC compiler does not work this way (tested in .NET 2003). When you
compile the sample with inlining enabled (like in default Release config),
the output is A1 = 1, A2 = 2. When run with inlining disabled (Debug),
output is A1 = 1, A2 = 1 - the compiler/linker uses the same version of the
A function in both compilation units, and it even gives no warning.

When I use "static inline" instead of "inline" for both A functions, it
works as expected. When I do not use any qualification (or use extern), the
linker gives error A is defined twice. My conclusion is current behaviour
with"inline" is both inconsistend and unsafe, as any compilation unit may
unknowningly use different inline function in case inline function is not
inlined (which is somethnig compiler is free to decide, and it is normal in
debug builds).

I recently experienced very similiar issue with global operator new - even
if it was inlined, it was shared accross various modules, leading to
unexpected behaviour. The issue was quite confusing, as I did not expect at
all other modules (in this case static libraries) could see my (inlined)
definition of operator new.

Regards
Ondrej

---------------------------------------
Ondrej Spanel
Lead Programmer
Bohemia Interactive Studio
www.bistudio.com
www.flashpoint1985.com


////////////////////////////////////////////////////////////////////////////
////////////
/// first.cpp
#include <stdio.h>
inline int A()
{
return 1;
}
int CallA2();

int CallA1()
{
return A();
}
int main(int argc, const char *argv[])
{
printf("A1 = %d\n",CallA1());
printf("A2 = %d\n",CallA2());
getchar();
return 0;
}
/// end of first.cpp

////////////////////////////////////////////////////////////////////////////
////////////
/// second.cpp
inline int A()
{
return 2;
}
int CallA2()
{
return A();
}
/// end of second.cpp
 
B

Bo Persson

Ondrej Spanel said:
Can anyone please confirm if this is bug (seems like that to me), or is
there some problem in the code provided?

No, it is not a bug. The problem is with your code.

Inline does not change the visiblity of the function, it just hints
the compiler that you want it inlined, if possible. C++ has a "one
definition rule" which says you are allowed to repeat the definition
of an inlines function, provided that all definitions are the same. In
your case they are obviously not.

*If* all functions are inlined, you might get away with the error,
because it is hard to detect the it. It is still an error though.


If you want functions local to a specific cpp-file, you can put them
in an anonymous namespace. That hides them from the outside (by
generating a unique name).


Bo Persson
Regards
Ondrej

Ondrej Spanel said:
I though that inline functions should be always visible only in the
compilation unit where they are defined - meaning if compiler
cannot
inline
them, they should be handled as if declared static. However sample attached
shows VC compiler does not work this way (tested in .NET 2003). When you
compile the sample with inlining enabled (like in default Release config),
the output is A1 = 1, A2 = 2. When run with inlining disabled (Debug),
output is A1 = 1, A2 = 1 - the compiler/linker uses the same
version of
the
A function in both compilation units, and it even gives no warning.

When I use "static inline" instead of "inline" for both A functions, it
works as expected. When I do not use any qualification (or use
extern),
the
linker gives error A is defined twice. My conclusion is current behaviour
with"inline" is both inconsistend and unsafe, as any compilation unit may
unknowningly use different inline function in case inline function is not
inlined (which is somethnig compiler is free to decide, and it is
normal
in
debug builds).

I recently experienced very similiar issue with global operator new - even
if it was inlined, it was shared accross various modules, leading to
unexpected behaviour. The issue was quite confusing, as I did not
expect
at
all other modules (in this case static libraries) could see my (inlined)
definition of operator new.

Regards
Ondrej

---------------------------------------
Ondrej Spanel
Lead Programmer
Bohemia Interactive Studio
www.bistudio.com
www.flashpoint1985.com
//////////////////////////////////////////////////////////////////////
//////
////////////
/// first.cpp
#include <stdio.h>
inline int A()
{
return 1;
}
int CallA2();

int CallA1()
{
return A();
}
int main(int argc, const char *argv[])
{
printf("A1 = %d\n",CallA1());
printf("A2 = %d\n",CallA2());
getchar();
return 0;
}
/// end of first.cpp
//////////////////////////////////////////////////////////////////////
//////
////////////
/// second.cpp
inline int A()
{
return 2;
}
int CallA2()
{
return A();
}
/// end of second.cpp
 
O

Ondrej Spanel

No, it is not a bug. The problem is with your code.
Inline does not change the visiblity of the function, it just hints
the compiler that you want it inlined, if possible. C++ has a "one
definition rule" which says you are allowed to repeat the definition
of an inlines function, provided that all definitions are the same. In
your case they are obviously not.

Thank you for your explanation. I searched the net and came to the same
conclusion. However there is still one thing which I am convinced is a bug
in Visual C++ - and that is that the problem in my code in undetected and
"random" function implementation is selected of those I provided. I would
expect to get some linker error or warning in such situation - and I think
it should be quite easy for the linker to see the two definitions are not
the same (maybe I am mistaken in this)?

Regards
Ondrej
Ondrej Spanel said:
I though that inline functions should be always visible only in the
compilation unit where they are defined - meaning if compiler
cannot
inline
them, they should be handled as if declared static. However sample attached
shows VC compiler does not work this way (tested in .NET 2003). When you
compile the sample with inlining enabled (like in default Release config),
the output is A1 = 1, A2 = 2. When run with inlining disabled (Debug),
output is A1 = 1, A2 = 1 - the compiler/linker uses the same
version of
the
A function in both compilation units, and it even gives no warning.

When I use "static inline" instead of "inline" for both A functions, it
works as expected. When I do not use any qualification (or use
extern),
the
linker gives error A is defined twice. My conclusion is current behaviour
with"inline" is both inconsistend and unsafe, as any compilation unit may
unknowningly use different inline function in case inline function is not
inlined (which is somethnig compiler is free to decide, and it is
normal
in
debug builds).

I recently experienced very similiar issue with global operator new - even
if it was inlined, it was shared accross various modules, leading to
unexpected behaviour. The issue was quite confusing, as I did not
expect
at
all other modules (in this case static libraries) could see my (inlined)
definition of operator new.

Regards
Ondrej

---------------------------------------
Ondrej Spanel
Lead Programmer
Bohemia Interactive Studio
www.bistudio.com
www.flashpoint1985.com
//////////////////////////////////////////////////////////////////////
//////
////////////
/// first.cpp
#include <stdio.h>
inline int A()
{
return 1;
}
int CallA2();

int CallA1()
{
return A();
}
int main(int argc, const char *argv[])
{
printf("A1 = %d\n",CallA1());
printf("A2 = %d\n",CallA2());
getchar();
return 0;
}
/// end of first.cpp
//////////////////////////////////////////////////////////////////////
//////
////////////
/// second.cpp
inline int A()
{
return 2;
}
int CallA2()
{
return A();
}
/// end of second.cpp
 
B

Bo Persson

Ondrej Spanel said:
Thank you for your explanation. I searched the net and came to the same
conclusion. However there is still one thing which I am convinced is a bug
in Visual C++ - and that is that the problem in my code in undetected and
"random" function implementation is selected of those I provided. I would
expect to get some linker error or warning in such situation - and I think
it should be quite easy for the linker to see the two definitions are not
the same (maybe I am mistaken in this)?

It is not really a bug, even though I agree that it would be nice if
the linker warned you.

The problem is that the linker isn't required to be C++ specific, only
the compiler is. On some systems the same linker is used for all
compilers, so the C++ cannot put any language specific requirements on
it.

Also, by not following the "one definition rule" technically you have
broken the contract with the compiler, and it can do just anything at
all. Issuing a warning is definitely allowed, but not required.


Bo Persson

Regards
Ondrej
I though that inline functions should be always visible only
in
the
compilation unit where they are defined - meaning if compiler cannot
inline
them, they should be handled as if declared static. However sample
attached
shows VC compiler does not work this way (tested in .NET
2003).
When you
compile the sample with inlining enabled (like in default
Release
config),
the output is A1 = 1, A2 = 2. When run with inlining disabled (Debug),
output is A1 = 1, A2 = 1 - the compiler/linker uses the same version of
the
A function in both compilation units, and it even gives no warning.

When I use "static inline" instead of "inline" for both A functions, it
works as expected. When I do not use any qualification (or use extern),
the
linker gives error A is defined twice. My conclusion is
current
behaviour
with"inline" is both inconsistend and unsafe, as any
compilation
unit may
unknowningly use different inline function in case inline
function
is not
inlined (which is somethnig compiler is free to decide, and it
is
normal
in
debug builds).

I recently experienced very similiar issue with global
operator
new - even
if it was inlined, it was shared accross various modules,
leading
to
unexpected behaviour. The issue was quite confusing, as I did
not
expect
at
all other modules (in this case static libraries) could see my (inlined)
definition of operator new.

Regards
Ondrej

---------------------------------------
Ondrej Spanel
Lead Programmer
Bohemia Interactive Studio
www.bistudio.com
www.flashpoint1985.com
//////////////////////////////////////////////////////////////////////
//////
////////////
/// first.cpp
#include <stdio.h>
inline int A()
{
return 1;
}
int CallA2();

int CallA1()
{
return A();
}
int main(int argc, const char *argv[])
{
printf("A1 = %d\n",CallA1());
printf("A2 = %d\n",CallA2());
getchar();
return 0;
}
/// end of first.cpp
//////////////////////////////////////////////////////////////////////
//////
////////////
/// second.cpp
inline int A()
{
return 2;
}
int CallA2()
{
return A();
}
/// end of second.cpp
 

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

Similar Threads


Top