I am surprised I cannot define a global const object in one file and
access it in another:
--------- x.cc ---------
const int a = 42
------------------------
--------- y.cc ---------
extern const int a;
int foo() { return a; }
------------------------
When I compile both sources to objects I see access to 'a' as
expected:
movl a(%rip), %eax
ret
But the object file x.o does not contain anything. Why?
If I remove the 'const' in the definition and in the extern
declaration it works as expected. Also if add an 'extern' to the
definition in x.cc so that it is
extern const int a = 42;
the object 'a' is created in x.o. Can someone explain this?
I am surprised I cannot define a global const object in one file and
access it in another:
--------- x.cc ---------
const int a = 42
------------------------
--------- y.cc ---------
extern const int a;
int foo() { return a; }
------------------------
When I compile both sources to objects I see access to 'a' as
expected:
movl a(%rip), %eax
ret
But the object file x.o does not contain anything. Why?
If I remove the 'const' in the definition and in the extern
declaration it works as expected. Also if add an 'extern' to the
definition in x.cc so that it is
extern const int a = 42;
the object 'a' is created in x.o. Can someone explain this?
I am surprised I cannot define a global const object in one file and
access it in another:
--------- x.cc ---------
const int a = 42
------------------------
--------- y.cc ---------
extern const int a;
int foo() { return a; }
------------------------
When I compile both sources to objects I see access to 'a' as
expected:
movl a(%rip), %eax
ret
But the object file x.o does not contain anything. Why?
If I remove the 'const' in the definition and in the extern
declaration it works as expected. Also if add an 'extern' to the
definition in x.cc so that it is
extern const int a = 42;
the object 'a' is created in x.o. Can someone explain this?
08.10.2021 23:47 Steve Keller kirjutas:
I am surprised I cannot define a global const object in one file and
access it in another:
They messed it up though with class static const members, which by some >reason did not follow the same rules and caused a lot of randomly
appearing obscure linker errors.
If I remove the 'const' in the definition and in the extern
declaration it works as expected. Also if add an 'extern' to the
definition in x.cc so that it is
extern const int a = 42;
the object 'a' is created in x.o. Can someone explain this?
Paavo Helde <myfirstname@osa.pri.ee> writes:
08.10.2021 23:47 Steve Keller kirjutas:
I am surprised I cannot define a global const object in one file and
access it in another:
They messed it up though with class static const members, which by some
reason did not follow the same rules and caused a lot of randomly
appearing obscure linker errors.
I would not characterize the linker errors as either random or obscure.
Annoying, yes. But the solution is simple, if not necessarily pretty.
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C
macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++ namespaces and cannot be undefined.
Const objects have internal linkage unless it is specified with
"extern". I think it's in 6.2.1 in C++17, but I won't swear to it.
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C
macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++
namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
red floyd <no.spam.here@its.invalid> writes:
Const objects have internal linkage unless it is specified with
"extern". I think it's in 6.2.1 in C++17, but I won't swear to it.
I thought I havd already used this like in C and it worked. But I'm obviously wrong since I tested with very old GNU C++ compiler and it
also shows this behavior.
But I wonder why C++ differs here from C when C already has 'static'
for this purpose. And why treat const and non-const so differently?
It means you have to use 'static' to make a non-const object internal
and 'extern' to make a const object external.
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C
macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++
namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
red floyd <no.spam.here@its.invalid> writes:
Const objects have internal linkage unless it is specified with
"extern". I think it's in 6.2.1 in C++17, but I won't swear to it.
I thought I havd already used this like in C and it worked. But I'm obviously wrong since I tested with very old GNU C++ compiler and it
also shows this behavior.
But I wonder why C++ differs here from C when C already has 'static'
for this purpose. And why treat const and non-const so differently?
It means you have to use 'static' to make a non-const object internal
and 'extern' to make a const object external.
Steve
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C
macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++
namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
It only causes duplication if you take the address and return a
pointer. Why do that for a constant defined in a header?
Bo Persson <bo@bo-persson.se> writes:
It only causes duplication if you take the address and return a
pointer. Why do that for a constant defined in a header?
But taking the address is very common, e.g. if the object is an array.
In fact, before I posted my first example with 'const int a = 42;' I
had observed the behavior with const char arrays. Here You see the duplication if you put it as non-extern const into a header file:
$ cat foo.hh
const char s[] = "This is a string";
void bar();
$ cat x.cc
#include <iostream>
#include "foo.hh"
void bar() { std::cout << s; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
int main()
{
bar();
std::cout << s;
}
$ g++ -Os -o foo x.cc y.cc
$ strings -a foo | grep This
This is a string
This is a string
For having only one string the duplicates need to be removed at link
time, so one needs -flto here. Also you should avoid to explicitly
define two different arrays as indeed these would need to be different objects.
With the following changes I get one string only in the final executable:
$ cat foo.hh
const char* const s = "This is a string";
void bar();
$ g++ -Os -o foo x.cc y.cc -flto
$ strings foo | grep 'This is'
This is a string
Paavo Helde <myfirstname@osa.pri.ee> writes:
For having only one string the duplicates need to be removed at link
time, so one needs -flto here. Also you should avoid to explicitly
define two different arrays as indeed these would need to be different
objects.
-flto doesn't help with the source that I have shown.
With the following changes I get one string only in the final executable:
$ cat foo.hh
const char* const s = "This is a string";
void bar();
$ g++ -Os -o foo x.cc y.cc -flto
$ strings foo | grep 'This is'
This is a string
Yes, but then you add a const pointer variable in each TU
10.10.2021 09:55 Steve Keller kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C
macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++
namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
The unused const objects are routinely optimized away be the compiler,
as you saw by yourself ("object file was empty").
It's true that for larger and more complicated objects this might not
work so well. So don't do that. Put the object in a single TU and
provide functions to access it. (Making the object extern is not safe
in general because of the "Static Initialization Order Fiasco".)
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
Paavo Helde <myfirstname@osa.pri.ee> writes:
10.10.2021 09:55 Steve Keller kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file
and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C >>>> macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++ >>>> namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
The unused const objects are routinely optimized away be the compiler,
as you saw by yourself ("object file was empty").
It's true that for larger and more complicated objects this might not
work so well. So don't do that. Put the object in a single TU and
provide functions to access it. (Making the object extern is not safe
in general because of the "Static Initialization Order Fiasco".)
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
It appears you have sidestepped the central question here. What a
definition like 'const int foo = 7;' (without any mention anywhere
of 'extern') does in C++ is, AFAICT, exactly the same as a similar
definition with static, namely 'static const int foo = 7;'. If
these two definitions are exactly the same (and I believe they are),
why change the meaning of the version that doesn't say 'static'?
Why introduce what appears to be a gratuitous incompatibility with C
when there was already a perfectly good construct that could be used
(and works in C++ now) for defining a local constant?
Paavo Helde <myfirstname@osa.pri.ee> writes:
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
It appears you have sidestepped the central question here. What a
definition like 'const int foo = 7;' (without any mention anywhere
of 'extern') does in C++ is, AFAICT, exactly the same as a similar
definition with static, namely 'static const int foo = 7;'.
On 2021-10-29 at 15:29, Tim Rentsch wrote:
Paavo Helde <myfir...@osa.pri.ee> writes:
10.10.2021 09:55 Steve Keller kirjutas:
Paavo Helde <myfir...@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file >>>> and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C >>>> macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++ >>>> namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n';
}
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
The unused const objects are routinely optimized away be the compiler,
as you saw by yourself ("object file was empty").
It's true that for larger and more complicated objects this might not
work so well. So don't do that. Put the object in a single TU and
provide functions to access it. (Making the object extern is not safe
in general because of the "Static Initialization Order Fiasco".)
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
It appears you have sidestepped the central question here. What a definition like 'const int foo = 7;' (without any mention anywhere
of 'extern') does in C++ is, AFAICT, exactly the same as a similar definition with static, namely 'static const int foo = 7;'. If
these two definitions are exactly the same (and I believe they are),
why change the meaning of the version that doesn't say 'static'?
Why introduce what appears to be a gratuitous incompatibility with C
when there was already a perfectly good construct that could be used
(and works in C++ now) for defining a local constant?
A problem here is that C++ introduced the const keyword first.
When C got it later, the C committee decided to do it slighly differently.
Now what?
On 2021-10-29 at 15:29, Tim Rentsch wrote:
Paavo Helde <myfirstname@osa.pri.ee> writes:
10.10.2021 09:55 Steve Keller kirjutas:
Paavo Helde <myfirstname@osa.pri.ee> writes:
Such global const definitions normally appear in a common header file >>>>> and would just cause duplicate linker symbols if they had external
linkage. Now they can be just optimized away in translation units
which do not use them.
I believe the original motivation was to have an easy replacement of C >>>>> macros in header files, i.e. instead of
#define a 42
one can easily use
const int a = 42;
which would function almost exactly like a #define, plus it honors C++ >>>>> namespaces and cannot be undefined.
If you write such "global" const objects into a header file they are
in fact not global, because the implicit 'static' makes them local to
file translation unit and this can even cause duplication:
$ cat foo.hh
const int a = 42;
const int *bar();
$ cat x.cc
#include "foo.hh"
const int *bar() { return &a; }
$ cat y.cc
#include <iostream>
#include "foo.hh"
const int *foo() { return &a; }
int main()
{
std::cout << (void *)foo() << '\n' << (void *)bar() << '\n'; >>>> }
$ g++ -Os -o foo x.cc y.cc
$ ./foo
0x56027d731008
0x56027d731004
For a small 'int' one may not care but for larger constant objects
this may be really bad.
The unused const objects are routinely optimized away be the compiler,
as you saw by yourself ("object file was empty").
It's true that for larger and more complicated objects this might not
work so well. So don't do that. Put the object in a single TU and
provide functions to access it. (Making the object extern is not safe
in general because of the "Static Initialization Order Fiasco".)
To avoid it, I think you still have to write the defintion into only
one C++ source file using 'extern'
extern const int = 42;
and put
extern const int a;
into the header file. I still don't see the advantage for C++ to
differ from C here.
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
It appears you have sidestepped the central question here. What a
definition like 'const int foo = 7;' (without any mention anywhere
of 'extern') does in C++ is, AFAICT, exactly the same as a similar
definition with static, namely 'static const int foo = 7;'. If
these two definitions are exactly the same (and I believe they are),
why change the meaning of the version that doesn't say 'static'?
Why introduce what appears to be a gratuitous incompatibility with C
when there was already a perfectly good construct that could be used
(and works in C++ now) for defining a local constant?
A problem here is that C++ introduced the const keyword first.
When C got it later, the C committee decided to do it slighly
differently.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Paavo Helde <myfirstname@osa.pri.ee> writes:
In some sense the do not differ. The const globals in C++ are
primarily meant for replacing C #define. Each C #define is TU-specific
and gets fully preprocessed by the preprocessor, no other TU-s are
involved.
It appears you have sidestepped the central question here. What a
definition like 'const int foo = 7;' (without any mention anywhere
of 'extern') does in C++ is, AFAICT, exactly the same as a similar
definition with static, namely 'static const int foo = 7;'.
Is that not dependent upon scope? For example:
class x {
static const unsigned long FRED = 0xabcdef00ul;
};
requires an additional declaration in a compilation unit, e.g.
const unsigned long x::FRED;
While
namespace y {
const unsigned long FRED = 0xabcdef00ul;
};
doesn't require an additional declaration.
scott@slp53.sl.home (Scott Lurndal) writes:
Is that not dependent upon scope? For example:
class x {
static const unsigned long FRED = 0xabcdef00ul;
};
Yes, it's true that leaving off 'static' here means something
significantly different. Note however, (a) neither of these
forms is allowed in C so there is no question of incompatibility;
(b) the 'static'-less form wasn't allowed until C++11; (c) only
the 'static' form works for the purpose of being usable in
constant expressions, so the question here is moot.
requires an additional declaration in a compilation unit, e.g.
const unsigned long x::FRED;
In my tests such a declaration was needed only if the address of
the static member FRED was taken. (I confess I didn't even try
to consult the C++ standard to see if that result is officially
okay or is merely a consequence of undefined behavior.)
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 113 |
Nodes: | 8 (1 / 7) |
Uptime: | 133:21:54 |
Calls: | 2,501 |
Files: | 8,696 |
Messages: | 1,925,604 |