Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #81933 > unrolled thread

Global const objects missing from object file

Started bySteve Keller <keller.steve@gmx.de>
First post2021-10-08 22:47 +0200
Last post2021-10-09 17:40 +0000
Articles 20 on this page of 25 — 10 participants

Back to article view | Back to comp.lang.c++


Contents

  Global const objects missing from object file Steve Keller <keller.steve@gmx.de> - 2021-10-08 22:47 +0200
    Re: Global const objects missing from object file red floyd <no.spam.here@its.invalid> - 2021-10-08 15:09 -0700
      Re: Global const objects missing from object file Steve Keller <keller.steve@gmx.de> - 2021-10-10 08:28 +0200
        Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-10 12:03 +0300
        Re: Global const objects missing from object file David Brown <david.brown@hesbynett.no> - 2021-10-10 12:29 +0200
    Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-09 10:47 +0300
      Re: Global const objects missing from object file scott@slp53.sl.home (Scott Lurndal) - 2021-10-09 14:32 +0000
        Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-09 21:39 +0300
      Re: Global const objects missing from object file Steve Keller <keller.steve@gmx.de> - 2021-10-10 08:55 +0200
        Re: Global const objects missing from object file Bo Persson <bo@bo-persson.se> - 2021-10-10 10:34 +0200
          Re: Global const objects missing from object file Steve Keller <keller.steve@gmx.de> - 2021-10-10 15:55 +0200
            Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-10 17:28 +0300
              Re: Global const objects missing from object file Steve Keller <keller.steve@gmx.de> - 2021-10-10 20:42 +0200
                Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-10 22:44 +0300
        Re: Global const objects missing from object file Paavo Helde <myfirstname@osa.pri.ee> - 2021-10-10 12:14 +0300
          Re: Global const objects missing from object file Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-10-29 06:29 -0700
            Re: Global const objects missing from object file Bo Persson <bo@bo-persson.se> - 2021-10-29 15:55 +0200
              Re: Global const objects missing from object file Öö Tiib <ootiib@hot.ee> - 2021-10-29 22:20 -0700
              Re: Global const objects missing from object file Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-11-07 04:51 -0800
            Re: Global const objects missing from object file scott@slp53.sl.home (Scott Lurndal) - 2021-10-29 14:44 +0000
              Re: Global const objects missing from object file Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-11-07 05:08 -0800
                Re: Global const objects missing from object file scott@slp53.sl.home (Scott Lurndal) - 2021-11-07 14:21 +0000
        Re: Global const objects missing from object file David Brown <david.brown@hesbynett.no> - 2021-10-10 12:33 +0200
    Re: Global const objects missing from object file "Alf P. Steinbach" <alf.p.steinbach@gmail.com> - 2021-10-09 15:05 +0200
    Re: Global const objects missing from object file Juha Nieminen <nospam@thanks.invalid> - 2021-10-09 17:40 +0000

Page 1 of 2  [1] 2  Next page →


#81933 — Global const objects missing from object file

FromSteve Keller <keller.steve@gmx.de>
Date2021-10-08 22:47 +0200
SubjectGlobal const objects missing from object file
Message-ID<sjqap1$sih$1@gioia.aioe.org>
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?

Steve

[toc] | [next] | [standalone]


#81935

Fromred floyd <no.spam.here@its.invalid>
Date2021-10-08 15:09 -0700
Message-ID<sjqfj7$5dn$1@redfloyd.dont-email.me>
In reply to#81933
On 10/8/2021 1:47 PM, Steve Keller wrote:
> 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?

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.

[toc] | [prev] | [next] | [standalone]


#81957

FromSteve Keller <keller.steve@gmx.de>
Date2021-10-10 08:28 +0200
Message-ID<sju174$1hf6$1@gioia.aioe.org>
In reply to#81935
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

[toc] | [prev] | [next] | [standalone]


#81960

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-10 12:03 +0300
Message-ID<sjua9t$csh$1@dont-email.me>
In reply to#81957
10.10.2021 09:28 Steve Keller kirjutas:
> 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.

Global objects have pretty limited use in C++, because of the "Static 
Initialization Order Fiasco". As soon as one such global object in one 
translation unit starts to depend on another global object in another 
translation unit, you cannot be sure any more they are constructed in 
the right order.

In C++ this is a bigger problem than in C as C++ relies heavily on 
constructors whose code would run before main() for global objects.

In practice, one typically hides global non-const objects away as a 
static object inside some function, or at least accessed only via 
functions in a single TU, which makes the object creation order much 
better controlled.

Const global objects are TU-specific by default, so the problem does not 
occur. As soon as you make them extern, the danger of the initialization 
fiasco appears, even for something so simple as an int.

[toc] | [prev] | [next] | [standalone]


#81962

FromDavid Brown <david.brown@hesbynett.no>
Date2021-10-10 12:29 +0200
Message-ID<sjuf9q$crf$1@dont-email.me>
In reply to#81957
On 10/10/2021 08:28, Steve Keller wrote:
> 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
> 

I think this goes back to early history (and I hope and expect to be
corrected if I've got it wrong).  "const" was first part of C++, before
being copied over to C.  So when it was introduced in C++ there was no
conflicting version in C.  Since one of the ideas behind it was to get a
better alternative to #define constants, it was important to be
convenient in headers, and that for common usage such as integer
constants, it could be as efficient - there was no need to make the
constant an actual allocated object in memory.  Add to that, the idea of
objects and identifiers being of external linkage by default is a
/major/ design mistake in C (IMHO, of course).  It is far better to have
things with internal linkage unless you /really/ want to make them
available in other units.  Perhaps making "const" objects "static" by
default was seen as a step to correct this.

So the question is why C didn't copy that aspect when they copied
"const".  I guess they thought it was simpler and more consistent to
have the same rules for const objects as for non-const objects.

In headers, I tend to be explicit about using "static" or "extern", even
when it might not be necessary - I prefer explicit and it's not uncommon
for a header to be usable from both C and C++.

[toc] | [prev] | [next] | [standalone]


#81939

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-09 10:47 +0300
Message-ID<sjrhdp$bta$1@dont-email.me>
In reply to#81933
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:
> 
> --------- 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?
> 

Yes, this is working as designed, in C++. I believe this is one of 
differences between C and C++.

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.

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.







[toc] | [prev] | [next] | [standalone]


#81946

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-10-09 14:32 +0000
Message-ID<NJh8J.40517$6u6.12262@fx03.iad>
In reply to#81939
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.

[toc] | [prev] | [next] | [standalone]


#81950

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-09 21:39 +0300
Message-ID<sjsnlu$dti$1@dont-email.me>
In reply to#81946
09.10.2021 17:32 Scott Lurndal kirjutas:
> 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.

If a linker errors start to appear after some straightforward code 
rewrite like replacing an if() with the ternary operator, and only with 
some compilers and only with some optimization options, surely they will 
look random and obscure if you have not encountered such issues before.

Yes, they are not obscure once you already understand the issue.

> Annoying, yes.   But the solution is simple, if not necessarily pretty.

IIRC at one point one had to use different solutions for different 
mainstream compilers, as there was no code variant accepted by both. But 
that was long ago.

[toc] | [prev] | [next] | [standalone]


#81958

FromSteve Keller <keller.steve@gmx.de>
Date2021-10-10 08:55 +0200
Message-ID<sju2pd$1ko$1@gioia.aioe.org>
In reply to#81939
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.


Steve

[toc] | [prev] | [next] | [standalone]


#81959

FromBo Persson <bo@bo-persson.se>
Date2021-10-10 10:34 +0200
Message-ID<isfms2F80esU1@mid.individual.net>
In reply to#81958
On 2021-10-10 at 08:55, Steve Keller wrote:
> 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.
> 

It only causes duplication if you take the address and return a pointer. 
Why do that for a constant defined in a header?

[toc] | [prev] | [next] | [standalone]


#81964

FromSteve Keller <keller.steve@gmx.de>
Date2021-10-10 15:55 +0200
Message-ID<sjurco$1nlj$1@gioia.aioe.org>
In reply to#81959
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

So, I still don't see the purpose of defining const global objects as
internal linkage implicitly so you can put them into a header file.
If I'd want that I could also put a 'static' qualifier.  But usually
you'd wouldn't want that anyway except for basic types and instead
define it once in one TU and declare it as external in the hear file
(if it's simple enough that initialization order doesn't matter).  And
then we would have more compatability to C and less surprise for C
programmers (which I have been for a long time).

Steve

[toc] | [prev] | [next] | [standalone]


#81965

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-10 17:28 +0300
Message-ID<sjutb4$dud$1@dont-email.me>
In reply to#81964
10.10.2021 16:55 Steve Keller kirjutas:
> 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

[toc] | [prev] | [next] | [standalone]


#81967

FromSteve Keller <keller.steve@gmx.de>
Date2021-10-10 20:42 +0200
Message-ID<sjvc6e$tpn$1@gioia.aioe.org>
In reply to#81965
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 and an
indirection with every access to the const object (it also probably
adds a number of entries to the relocation table of the executable
binary slowing startup).  And I wouldn't like the superfluous
indirection when the object is at a fixed known address.  Defining
only one object of type

   const char[]

with external linkage is preferable IMHO.  Having read in this thread
that 'const' probably originated in C++ and the designers felt that
default external linkage was wrong in the beginning, I begin to
understand the reasoning behind the C++ const behavior.  Whether I can
make myself to like it, ... I don't know.

Steve

[toc] | [prev] | [next] | [standalone]


#81969

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-10 22:44 +0300
Message-ID<sjvfrq$gu0$1@dont-email.me>
In reply to#81967
10.10.2021 21:42 Steve Keller kirjutas:
> 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 

In each TU which uses it, most probably, and even then it has good 
chances to be completely optimized away.

And we need to put this thing into context. For example, a set of CUDA 
runtime libraries is 960 MB. A pointer of 8 bytes, duplicated in 10 TU-s 
which make use of it would consume 80 bytes. This is 0.000008% of CUDA 
libraries. Nobody will care about such things nowadays (except a certain 
one frequent poster in this group, and this is not me).

[toc] | [prev] | [next] | [standalone]


#81961

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2021-10-10 12:14 +0300
Message-ID<sjuau5$h17$1@dont-email.me>
In reply to#81958
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.

[toc] | [prev] | [next] | [standalone]


#82173

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-10-29 06:29 -0700
Message-ID<861r44ez7k.fsf@linuxsc.com>
In reply to#81961
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?

[toc] | [prev] | [next] | [standalone]


#82178

FromBo Persson <bo@bo-persson.se>
Date2021-10-29 15:55 +0200
Message-ID<iu2cqjF75nU1@mid.individual.net>
In reply to#82173
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.

Now what?
 
 

[toc] | [prev] | [next] | [standalone]


#82181

FromÖö Tiib <ootiib@hot.ee>
Date2021-10-29 22:20 -0700
Message-ID<8706956d-b2a2-414b-abca-d5bfa8ef2d63n@googlegroups.com>
In reply to#82178
On Friday, 29 October 2021 at 16:55:47 UTC+3, Bo Persson wrote:
> 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?

Now we have to live with it. C+11 tried to add some clarity with constexpr
and C++17 to turn it all into mess with (sometimes also implicit) inline.

[toc] | [prev] | [next] | [standalone]


#82259

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2021-11-07 04:51 -0800
Message-ID<86mtmgb02h.fsf@linuxsc.com>
In reply to#82178
Bo Persson <bo@bo-persson.se> writes:

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

These statements leave out some important parts of the story.

No question that const appeared first in early versions of C++.

Not long after that however const was assimilated into working C
compilers (and years before ANSI C was ratified).  So a basis for
comparison was evident pretty early.

The question here though is not about const but about changing
the C linkage model.  It was obvious from day one that using
const without a storage class to mean internal linkage is a
departure from the C linkage model.  And an unnecessary one:  to
the best of my knowledge 'static const <type> whatever;'  has
always worked in C++ the same as without the 'static'.  Allowing
a redundant form gives rise to a gratuitous incompatibility.

In the late 1980s not many people were using C++, and C++ was
itself in a state of flux.  It would have been easy at that time
to abandon the rule that const-without-static had internal
linkage, getting rid of the oddball linkage exception, and
restore compatibility with C rules (by then the ANSI C efforts
were far enough along that one could see what those rules would
be post-standardization).

I must admit it irks me more than a little bit that C++'s idea of
staying compatible with C is always for C to change to make C
more like C++, and never the other way around.

[toc] | [prev] | [next] | [standalone]


#82179

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-10-29 14:44 +0000
Message-ID<gNTeJ.2393$VS2.529@fx44.iad>
In reply to#82173
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.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c++


csiph-web