Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

why inline function doen't "inlined"

99 views
Skip to first unread message

w...@totalbb.net.tw

unread,
Feb 12, 2018, 11:38:30 PM2/12/18
to
The compiled program dosn't indicate sin2 is the same as ::sin

---------- file.cpp ---------
#include <iostream>
#include <cmath>

inline __attribute__((always_inline))
double sin2(double x) { return ::sin(x); }

int main()
{
std::cout << (void*)::sin << std::endl;
std::cout << (void*)sin2 << std::endl;
return 0;
}
-----------------------------

$ g++ file.cpp
$ ./a.out
0x400680
0x40085d

Why is that? How to fix it?

Ian Collins

unread,
Feb 13, 2018, 12:40:42 AM2/13/18
to
Nothing is broken - you can't take the address of something that has
been inlined. Even if it were, gcc won't inline functions without
optimisation enabled.

--
Ian.

Christian Gollwitzer

unread,
Feb 13, 2018, 12:45:47 AM2/13/18
to
Am 13.02.18 um 05:38 schrieb w...@totalbb.net.tw:
Because you are taking the address of it. The address will always be
different and no indicator for inlining. If you want to check inlining,
you should check the assembly output of code invoking the function (-S
switch)

Furthermore, if you compile with optimizations, the call to "sin" might
decay into a special instruction depending on your platform, with no
"call" instruction visible at all.

If you want to create a symbol alias, use "using".


Christian

Juha Nieminen

unread,
Feb 13, 2018, 2:00:50 AM2/13/18
to
w...@totalbb.net.tw wrote:
> The compiled program dosn't indicate sin2 is the same as ::sin

Firstly, 'inline' is a linker instruction, and nowadays has nothing to do
with actual inlining, as strange as it might sound. (It tells the compiler
that if the implementation of the function appears in more than one
compilation unit, ie. more than one object file, for the linker to merge
them, ie. use only one of them and make everything call that one.)
It might have affected compiler behavior in terms of actual inlining
in the distant past, but nowadays most compilers probably just ignore
it completely when making inlining decisions.

Secondly, taking the address of an "inline" function will create an
actual instance of the function, because the address to that function
has to point somewhere, and it has to be unique. (Although I could be
talking out of my ass here, since I don't know what the standard says
about inline functions and taking their addresses.) However, just
because you took the address of the function, forcing the compiler
to actually instantiate it, that doesn't stop the compiler from
still inlining it. The implementation of the function could exist
in the final executable, yet it could have still been inlined
everywhere where it was called. So execution never actually jumps
to the function. It's just that when you took the address, it has
to point somewhere that actually exists. It has to be able to use
that address (eg. to print it).

David Brown

unread,
Feb 13, 2018, 3:26:10 AM2/13/18
to
gcc /will/ inline functions that have __attribute__((always_inline)),
even without optimisations enabled.

But of course it can't inline a function when you take the address of
that function. (It will still inline calls to sin2 from elsewhere in
the code.)

David Brown

unread,
Feb 13, 2018, 3:39:45 AM2/13/18
to
On 13/02/18 08:00, Juha Nieminen wrote:
> w...@totalbb.net.tw wrote:
>> The compiled program dosn't indicate sin2 is the same as ::sin
>
> Firstly, 'inline' is a linker instruction, and nowadays has nothing to do
> with actual inlining, as strange as it might sound. (It tells the compiler
> that if the implementation of the function appears in more than one
> compilation unit, ie. more than one object file, for the linker to merge
> them, ie. use only one of them and make everything call that one.)
> It might have affected compiler behavior in terms of actual inlining
> in the distant past, but nowadays most compilers probably just ignore
> it completely when making inlining decisions.

That is a somewhat true, but not entirely accurate. If a non-static
function (or variable, in C++17) is marked "inline" then you can have
more than one definition for the function in different translation units
in the program, but they must all be identical. If the function's
address is taken, you get the same address in all translation units.

It does not mean that the function must be inlined - but many compilers
take it as a strong hint that the function should be inlined, depending
on optimisation levels. It is common not to do any inlining when using
no optimisation, to treat it as a hint when doing some optimisation, and
to ignore it for heavy optimisation (when the compiler does much more
analysis). The gcc attribute "always_inline", however, tells the
compiler to inline the function whenever it is legally possible.

If the compiler does not need a non-inlined version of the function
(because all calls in the current translation unit get inlined, and you
don't take its address), then it does not need to generate the
non-inlined version, even if the function has external linkage.

>
> Secondly, taking the address of an "inline" function will create an
> actual instance of the function, because the address to that function
> has to point somewhere, and it has to be unique. (Although I could be
> talking out of my ass here, since I don't know what the standard says
> about inline functions and taking their addresses.)

AFAIK, you are correct here.

> However, just
> because you took the address of the function, forcing the compiler
> to actually instantiate it, that doesn't stop the compiler from
> still inlining it.

Correct. The compiler can inline some uses of the function while using
a non-inlined version in other cases.

> The implementation of the function could exist
> in the final executable, yet it could have still been inlined
> everywhere where it was called. So execution never actually jumps
> to the function. It's just that when you took the address, it has
> to point somewhere that actually exists. It has to be able to use
> that address (eg. to print it).
>

(I think technically that the compiler does not have to generate a
non-inlined version even if you have taken its address - if the compiler
is sure you never call it via that address, such as in this sample
program. All that is needed then is the program-wide unique address,
not the function implementation. But I think that would take a lot of
sophistication and link-time optimisation to achieve.)


Paavo Helde

unread,
Feb 13, 2018, 8:15:41 AM2/13/18
to
On 13.02.2018 6:38, w...@totalbb.net.tw wrote:
> The compiled program dosn't indicate sin2 is the same as ::sin
>
> ---------- file.cpp ---------
> #include <iostream>
> #include <cmath>
>
> inline __attribute__((always_inline))
> double sin2(double x) { return ::sin(x); }
>
> int main()
> {
> std::cout << (void*)::sin << std::endl;
> std::cout << (void*)sin2 << std::endl;
> return 0;
> }

While others have explained why the addresses appear different, I would
also like to add a remark that inlining is most probably irrelevant for
such a function (taking a single argument and calling sin()). This is
because sine calculation is a pretty heavyweight operation, so any
potential performance gain from inlining would probably turn out
unmeasurable.

Of course, if you want to put that function in a header then inline is
needed for avoiding linker errors. But this has actually nothing to do
with inlining.

hth
Paavo





David Brown

unread,
Feb 13, 2018, 8:30:44 AM2/13/18
to
On 13/02/18 14:15, Paavo Helde wrote:
> On 13.02.2018 6:38, w...@totalbb.net.tw wrote:
>> The compiled program dosn't indicate sin2 is the same as ::sin
>>
>> ---------- file.cpp ---------
>> #include <iostream>
>> #include <cmath>
>>
>> inline __attribute__((always_inline))
>> double sin2(double x) { return ::sin(x); }
>>
>> int main()
>> {
>> std::cout << (void*)::sin << std::endl;
>> std::cout << (void*)sin2 << std::endl;
>> return 0;
>> }
>
> While others have explained why the addresses appear different, I would
> also like to add a remark that inlining is most probably irrelevant for
> such a function (taking a single argument and calling sin()). This is
> because sine calculation is a pretty heavyweight operation, so any
> potential performance gain from inlining would probably turn out
> unmeasurable.

It is a good point to consider - certainly if you are thinking of
"inline" to improve speed, you need to look at the bigger picture.
However, it is not quite as simple as you suggest here.

First - clearly you need to enable optimisation if you are at all
concerned about performance. And if floating point performance is
important, "-ffast-math" can make a big difference.

Secondly, inlined code (whether due to "inline", or by making the
function "static" and letting the compiler figure it out) can have other
optimisation effects. Even if the call to the library sin() function
(or x86 sin opcode, which may or may not be faster) takes longer, having
the code inlined lets the compiler re-arrange instructions around the
calculation. The sine calculation may take 100 clock cycles - but
fetching of data from main memory can twice that, and inlining may let
the compiler start a fetch while the calculation is in progress.

>
> Of course, if you want to put that function in a header then inline is
> needed for avoiding linker errors. But this has actually nothing to do
> with inlining.
>

It is also best to make it "static inline", rather than just "inline".
You don't actually want it to be a symbol with external linkage.


James R. Kuyper

unread,
Feb 13, 2018, 11:34:03 AM2/13/18
to
On 02/12/2018 11:38 PM, w...@totalbb.net.tw wrote:
> The compiled program dosn't indicate sin2 is the same as ::sin
>
> ---------- file.cpp ---------
> #include <iostream>
> #include <cmath>
>
> inline __attribute__((always_inline))
> double sin2(double x) { return ::sin(x); }

Note: ::sin() is declared in <math.h>; <cmath> declares std::sin(). That
your code compiled successfully implies that <cmath> also declares
::sin(), but that is not required by the standard, and you shouldn't
write code that depends upon it.

> int main()
> {
> std::cout << (void*)::sin << std::endl;

Only pointers to object types can be converted to (void*) with defined
behavior.

> std::cout << (void*)sin2 << std::endl;

What you can do, instead of printing out those pointers, is simply
indicate whether they compare equal:

std::cout << (sin2 == ::sin) << std::endl;

> return 0;
> }
> -----------------------------
>
> $ g++ file.cpp
> $ ./a.out
> 0x400680
> 0x40085d
>
> Why is that? How to fix it?

Others have told you that you can't inline functions that you've taken
the address of. That's not quite the right way to describe the problem.
The problem is that an inlined function doesn't have an address, so if
you request the address of an inlined function, by that very act, you
are also requesting that the compiler generate an actual function that
the address can point to. This doesn't prevent calls to sin2() from
being inlined, and they probably will be, because gcc promises so when
you use the always_inlined attribute.

sin2() is a separate function from ::sin(), regardless of inlining. You
seem to have been expecting the compiler to notice that sin2() happens
to be a complete wrapper for ::sin(), and therefore equivalent to it.
That's not how it works.
If you want sin2 to be an expression that points to the same function as
::sin, that's easy to arrange:

auto const sin2 = ::sin;

Paavo Helde

unread,
Feb 13, 2018, 11:49:43 AM2/13/18
to
On 13.02.2018 15:30, David Brown wrote:

> Secondly, inlined code (whether due to "inline", or by making the
> function "static" and letting the compiler figure it out) can have other
> optimisation effects. Even if the call to the library sin() function
> (or x86 sin opcode, which may or may not be faster) takes longer, having
> the code inlined lets the compiler re-arrange instructions around the
> calculation. The sine calculation may take 100 clock cycles - but
> fetching of data from main memory can twice that, and inlining may let
> the compiler start a fetch while the calculation is in progress.

Point taken.

>
> It is also best to make it "static inline", rather than just "inline".
> You don't actually want it to be a symbol with external linkage.

I have understood that "static" is not needed for inlining to happen,
isn't this so? The compiler can both inline the function and generate an
external linkage version of it as well (which may be later discarded by
the linker if it is not used).

And should we not prefer anonymous namespace to static in C++?

cheers
paavo


w...@totalbb.net.tw

unread,
Feb 13, 2018, 10:05:25 PM2/13/18
to
What has presented is a (mis)reduced version of the real problem,
because the result is different from file to file, difficult to
reproduce (and I almost forgotten I can't expect the address of
inlined function be identical ,not by what the standard says but
by the semantics, or user's common understanding.

Actually, I were trying to wrap ::pow10 (manpage says this is a
GNU extension)

namespce Ns {
inline float pow10(float v) { return ::pow10f(v); };
inline double pow10(double v) { return ::pow10(v); };
inline long double pow10(long double v) { return ::pow10l(v); };
};

To keep things in topic, I tried evaluate
"auot const sin2=::sin;" in older style:

typedef float (& Math_f)(float);
typedef double (& Math_d)(double);

namespace Ns{
const Math_f pow10(::pow10f);
const Math_d pow10(::pow10);
};

But:
$g++ file.cpp
file.cpp: error: conflicting declaration ‘double (& Ns::pow10)(double)’
const Math_d pow10(::pow10);

So, this problem is still hanging there!

Jorgen Grahn

unread,
Feb 14, 2018, 1:50:12 AM2/14/18
to
On Wed, 2018-02-14, w...@totalbb.net.tw wrote:
> On Wednesday, February 14, 2018 at 12:34:03 AM UTC+8, James R. Kuyper wrote:
...

> What has presented is a (mis)reduced version of the real problem,

Yes, I wondered what you really wanted to do.

> because the result is different from file to file, difficult to
> reproduce (and I almost forgotten I can't expect the address of
> inlined function be identical ,not by what the standard says but
> by the semantics, or user's common understanding.
>
> Actually, I were trying to wrap ::pow10 (manpage says this is a
> GNU extension)
>
> namespce Ns {
> inline float pow10(float v) { return ::pow10f(v); };
> inline double pow10(double v) { return ::pow10(v); };
> inline long double pow10(long double v) { return ::pow10l(v); };
> };

[To non-Linux readers: these three GNU functions take a float, double
and long double respectively.]

Well, that code looks simple and correct to me. (Except I'm not sure
which overload is picked if you call Ns::pow10() with an int or
similar.)

I didn't have time to understand the rest (below) though. What do you
need it for?

> To keep things in topic, I tried evaluate
> "auot const sin2=::sin;" in older style:
>
> typedef float (& Math_f)(float);
> typedef double (& Math_d)(double);
>
> namespace Ns{
> const Math_f pow10(::pow10f);
> const Math_d pow10(::pow10);
> };
>
> But:
> $g++ file.cpp
> file.cpp: error: conflicting declaration ‘double (& Ns::pow10)(double)’
> const Math_d pow10(::pow10);
>
> So, this problem is still hanging there!

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Ian Collins

unread,
Feb 14, 2018, 2:09:28 AM2/14/18
to
On 02/14/2018 04:05 PM, w...@totalbb.net.tw wrote:
>
> What has presented is a (mis)reduced version of the real problem,
> because the result is different from file to file, difficult to
> reproduce (and I almost forgotten I can't expect the address of
> inlined function be identical ,not by what the standard says but
> by the semantics, or user's common understanding.
>
> Actually, I were trying to wrap ::pow10 (manpage says this is a
> GNU extension)
>
> namespce Ns {
> inline float pow10(float v) { return ::pow10f(v); };
> inline double pow10(double v) { return ::pow10(v); };
> inline long double pow10(long double v) { return ::pow10l(v); };
> };

Using inline, which is only a hint, is pretty pointless here. First off
the functions probably will be inlined and secondly even if they
weren't, the call overhead would be insignificant.

You will also hit ambiguity problems with calls like "pow10(2);" or
passing anything that isn't a floating point type.

Finally, loose all those superfluous semicolons!

--
Ian.

James R. Kuyper

unread,
Feb 14, 2018, 8:50:37 AM2/14/18
to
On 02/13/2018 10:05 PM, w...@totalbb.net.tw wrote:
> On Wednesday, February 14, 2018 at 12:34:03 AM UTC+8, James R. Kuyper wrote:
...
>> Others have told you that you can't inline functions that you've taken
>> the address of. That's not quite the right way to describe the problem.
>> The problem is that an inlined function doesn't have an address, so if
>> you request the address of an inlined function, by that very act, you
>> are also requesting that the compiler generate an actual function that
>> the address can point to. This doesn't prevent calls to sin2() from
>> being inlined, and they probably will be, because gcc promises so when
>> you use the always_inlined attribute.
>>
>> sin2() is a separate function from ::sin(), regardless of inlining. You
>> seem to have been expecting the compiler to notice that sin2() happens
>> to be a complete wrapper for ::sin(), and therefore equivalent to it.
>> That's not how it works.
>> If you want sin2 to be an expression that points to the same function as
>> ::sin, that's easy to arrange:
>>
>> auto const sin2 = ::sin;
>
> What has presented is a (mis)reduced version of the real problem,
> because the result is different from file to file, difficult to
> reproduce (and I almost forgotten I can't expect the address of
> inlined function be identical ,not by what the standard says but
> by the semantics, or user's common understanding.

That's true only of inline functions with internal linkage - a separate
actual definition of such a function will be created for each
translation unit in which you take it's address. However, "... An inline
function or variable with external linkage shall have the same address
in all translation units. ..." (10.1.6p6).

> Actually, I were trying to wrap ::pow10 (manpage says this is a
> GNU extension)
>
> namespce Ns {
> inline float pow10(float v) { return ::pow10f(v); };
> inline double pow10(double v) { return ::pow10(v); };
> inline long double pow10(long double v) { return ::pow10l(v); };
> };
>
> To keep things in topic, I tried evaluate
> "auot const sin2=::sin;" in older style:
>
> typedef float (& Math_f)(float);
> typedef double (& Math_d)(double);
>
> namespace Ns{
> const Math_f pow10(::pow10f);
> const Math_d pow10(::pow10);
> };
>
> But:
> $g++ file.cpp
> file.cpp: error: conflicting declaration ‘double (& Ns::pow10)(double)’
> const Math_d pow10(::pow10);

The problem is that Ns::pow10 is a reference to a function, it's not
itself a function. As a result, it cannot be overloaded.
If you need overloading, you'll have to define wrapper functions, and
the wrapper functions will unavoidably have addresses (if you take their
addresses) even if inlined, that are different from the addresses of the
function they wrap. That's not a problem - calls to one of the wrappers
will still be inlined. And if the existence of the actual functions
wasting space bothers you, remove the code that takes the address of
those functions - then the compiler will have no need to create them.

w...@totalbb.net.tw

unread,
Feb 14, 2018, 9:41:46 AM2/14/18
to
On Wednesday, February 14, 2018 at 3:09:28 PM UTC+8, Ian Collins wrote:
> On 02/14/2018 04:05 PM, w...@totalbb.net.tw wrote:
> >
> > What has presented is a (mis)reduced version of the real problem,
> > because the result is different from file to file, difficult to
> > reproduce (and I almost forgotten I can't expect the address of
> > inlined function be identical ,not by what the standard says but
> > by the semantics, or user's common understanding.
> >
> > Actually, I were trying to wrap ::pow10 (manpage says this is a
> > GNU extension)
> >
> > namespce Ns {
> > inline float pow10(float v) { return ::pow10f(v); };
> > inline double pow10(double v) { return ::pow10(v); };
> > inline long double pow10(long double v) { return ::pow10l(v); };
> > };
>
> Using inline, which is only a hint, is pretty pointless here. First off
> the functions probably will be inlined and secondly even if they
> weren't, the call overhead would be insignificant.
>

These codes are in a header file. If definition is given and not inline,
complier would say multiple definition error.

> You will also hit ambiguity problems with calls like "pow10(2);" or
> passing anything that isn't a floating point type.

Is'nt that ambiguity problem for all kind of function overloads?

> Finally, loose all those superfluous semicolons!
For detecting language changes, at least.

w...@totalbb.net.tw

unread,
Feb 14, 2018, 9:53:45 AM2/14/18
to
How unfortunate!
I was surprised for a moment that such overloading problems can be
solved by reference overload. Probably future C++ might consider adding
such function reference overload.

James R. Kuyper

unread,
Feb 14, 2018, 10:19:58 AM2/14/18
to
On 02/14/2018 09:41 AM, w...@totalbb.net.tw wrote:
> On Wednesday, February 14, 2018 at 3:09:28 PM UTC+8, Ian Collins wrote:
>> On 02/14/2018 04:05 PM, w...@totalbb.net.tw wrote:
...
>>> namespce Ns {
>>> inline float pow10(float v) { return ::pow10f(v); };
>>> inline double pow10(double v) { return ::pow10(v); };
>>> inline long double pow10(long double v) { return ::pow10l(v); };
>>> };
>>
>> Using inline, which is only a hint, is pretty pointless here. First off
>> the functions probably will be inlined and secondly even if they
>> weren't, the call overhead would be insignificant.
>>
>
> These codes are in a header file. If definition is given and not inline,
> complier would say multiple definition error.

Actually, it's detected by the linker, not the compiler. At compile
time, there's only one definition. You don't have multiple definitions
until it's time for multiple translation units to be linked together. If
your compiler automatically invokes the linker, it can be difficult to
notice the distinction.

You can avoid that problem by giving them internal linkage. However,
many compilers (quite rightly) give you warnings if you declare a
function with internal linkage, but don't actually use it anywhere in
the same translation unit. That's because it's the only translation unit
where such a function could be used.

...
>> Finally, loose all those superfluous semicolons!
> For detecting language changes, at least.

Which language changes are you thinking of? A semicolon after a function
definition has always been superfluous, even back in C.

James R. Kuyper

unread,
Feb 14, 2018, 10:20:16 AM2/14/18
to
On 02/14/2018 09:53 AM, w...@totalbb.net.tw wrote:
> On Wednesday, February 14, 2018 at 9:50:37 PM UTC+8, James R. Kuyper wrote:
>> On 02/13/2018 10:05 PM, w...@totalbb.net.tw wrote:
...
>>> What has presented is a (mis)reduced version of the real problem,
>>> because the result is different from file to file, difficult to
>>> reproduce (and I almost forgotten I can't expect the address of
>>> inlined function be identical ,not by what the standard says but
>>> by the semantics, or user's common understanding.
>>
>> That's true only of inline functions with internal linkage - a separate
>> actual definition of such a function will be created for each
>> translation unit in which you take it's address. However, "... An inline
>> function or variable with external linkage shall have the same address
>> in all translation units. ..." (10.1.6p6).
>
> How unfortunate!

Why do you consider that unfortunate?

Paavo Helde

unread,
Feb 14, 2018, 3:46:03 PM2/14/18
to
No, if you provide enough overloads, or better yet, a template to take
care of any new primitive types added in the future:

namespace Ns {
inline float pow10(float v) { return ::pow10f(v); };
template<typename T> double pow10(T v) { return ::pow10(v); };

Paavo Helde

unread,
Feb 14, 2018, 4:02:53 PM2/14/18
to
On 14.02.2018 16:41, w...@totalbb.net.tw wrote:
>>> namespce Ns {
>>> inline float pow10(float v) { return ::pow10f(v); };
>>> inline double pow10(double v) { return ::pow10(v); };
>>> inline long double pow10(long double v) { return ::pow10l(v); };
>>> };

In addition, be warned that adding a function in a namespace with the
same name as a function in the global namespace is not a good idea,
especially if it takes the same number of arguments. Yes, you can make
that work, but it's still error-prone and you will lose some extra hair
because of this in the future ;-)


David Brown

unread,
Feb 15, 2018, 4:43:14 AM2/15/18
to
"static" is certainly not necessary for inlining. But if you don't make
a variable or function "static" (or in an anonymous namespace, or
default static such as const variables) it will have external linkage -
the compiler needs to make a copy available for external use, and you
can't reuse that same identifier elsewhere in the program. A function
"sin2" in foo.c blocks you from having a function "sin2" in bar.c. If
the first "sin2" is inline, then all definitions of it in the program
must be inline and have the same definition - if it is not inline, then
you can't have any other definitions in the program.

And although the linker /might/ discard the unnecessary non-inlined
versions of the non-static function that gets inlined, it is not
guaranteed - that depends on the toolchain and the flags.

I think this is a flaw in the design of the earliest version of C -
file-level identifiers should have been effectively "static" by default,
and need explicit "exporting". We still live with the consequences of
that flaw in C and C++, precisely because few programmers are good
enough at always using "static" (or anonymous namespaces) at every
opportunity, thus files are bloated, links take longer, and name
collisions cause unnecessary trouble.

> And should we not prefer anonymous namespace to static in C++?
>

Anonymous namespaces provide an alternative to using "static". I
disagree that it is something we should "prefer" in C++ - it can make
sense for grouping several things together, but for a stand-alone item
then "static" is perfectly good and does the same job. AFAIK, there is
no difference between writing:

namespace {
int foo(int x) { return x * x; }
}

and

static int foo(int x) { return x * x; }




Alf P. Steinbach

unread,
Feb 15, 2018, 5:21:43 AM2/15/18
to
On 15.02.2018 10:42, David Brown wrote:
> AFAIK, there is no difference between writing:
>
> namespace {
> int foo(int x) { return x * x; }
> }
>
> and
>
> static int foo(int x) { return x * x; }

In C++03 a function needed to have external linkage in order to be used
for a template function pointer parameter.

It's possible but unlikely (considering that local types now can be
used) that that restriction still applies in C++11 and later.


Cheers!,

- Alf

Chris Vine

unread,
Feb 15, 2018, 8:53:52 AM2/15/18
to
On Thu, 15 Feb 2018 10:42:56 +0100
David Brown <david...@hesbynett.no> wrote:
[snip]
> Anonymous namespaces provide an alternative to using "static". I
> disagree that it is something we should "prefer" in C++ - it can make
> sense for grouping several things together, but for a stand-alone item
> then "static" is perfectly good and does the same job. AFAIK, there
> is no difference between writing:
>
> namespace {
> int foo(int x) { return x * x; }
> }
>
> and
>
> static int foo(int x) { return x * x; }

In C++98/03, anonymous namespaces had external linkage, not internal
linkage. Instead, the compiler would mangle the exported name into a
unique identifier which was guaranteed not to clash with the same name
used in a different namespace, provided that they had a C++ linkage
specification.

This was a fairly mad approach and was changed in C++11 so that names
in an anonymous namespace have only internal linkage (that is, the
anonymous namespace in C++11 has the same effect as the 'static'
keyword). The proviso I have mentioned was a trap for the unwary:
declaring a function in anonymous namespace as extern "C" (say in order
to use it as a callback to a C function) suppressed name mangling, with
the result that in C++98/03 it was as if the anonymous namespace were
ignored and the identifier were injected into the global namespace.

Chris

James R. Kuyper

unread,
Feb 16, 2018, 9:25:18 AM2/16/18
to
On 02/13/2018 11:49 AM, Paavo Helde wrote:
...
> And should we not prefer anonymous namespace to static in C++?

I knew that term didn't sound right, and I couldn't find it when I
searched the standard. That's because the standard uses the term
"unnamed namespace".

Alf P. Steinbach

unread,
Feb 16, 2018, 9:48:59 AM2/16/18
to
Let's compromise and call it "nameless".

Cheers!,

- Alf

0 new messages