Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c++ Subject: Re: Global const objects missing from object file Date: Sun, 07 Nov 2021 04:51:50 -0800 Organization: A noiseless patient Spider Lines: 120 Message-ID: <86mtmgb02h.fsf@linuxsc.com> References: <861r44ez7k.fsf@linuxsc.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="2dc722b95f3891b2f37c442b9fb0adbf"; logging-data="26363"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19pU3GQnFth6ZQq5DsUx0T2ywgzy2Hphf8=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:PyRt0a58SG3m4bYxFNJ4nVg6g0A= sha1:QI1tbJjjvpclmo024B4gq7TJmUI= Xref: csiph.com comp.lang.c++:82259 Bo Persson writes: > On 2021-10-29 at 15:29, Tim Rentsch wrote: > >> Paavo Helde writes: >> >>> 10.10.2021 09:55 Steve Keller kirjutas: >>> >>>> Paavo Helde 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 >>>> #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 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.