Re: Const declaration in header files

Discussion in 'C++' started by James Kanze, May 25, 2008.

  1. James Kanze

    James Kanze Guest

    On May 24, 10:46 pm, Paavo Helde <> wrote:
    > "Stephen Howe" <sjhoweATdialDOTpipexDOTcom> kirjutas:
    > > Just going over some grey areas in my knowledge in C++:


    > > 1) If I have


    > > const int SomeConst = 1;


    > > in a header file, it is global, and it is included in
    > > multiple translations units, but it is unused, I know that
    > > it does not take up storage in the final executable.


    > If something is unused, the compiler can throw it out on
    > "as-if" basis, or then not. This is mostly QOI issue. If the
    > variable definitions are incorrect and the standard requires a
    > diagnostic about that, the implementation has to produce the
    > diagnostic regardless of whether he would encode the variables
    > in the executable or not.


    > If the code happens to take the address of i somewhere, the
    > compiler is obliged to ensure that at runtime there will be an
    > int variable present with the proper value, so that the
    > address can be taken. This most probably means that the value
    > is somehow encoded in the executable - I guess this is what
    > you mean when you talk about storage in the executable.


    The as-if rule holds here as well. Probably the most frequence
    case of "taking the address" of an int const is when passing it
    to an int const& argument; such arguments generally only result
    from the expansion of a template, and in the absense of export,
    the compiler has access to the source code of the function, and
    can (potentially, at least) see if in fact, it could use the
    value directly just as well. Thus, if you have an
    std::vector<int>, and do a push_back( SomeConst ) on it, there's
    a very good chance that the compiler will not need to allocate
    memory for SomeConst then either, despite the fact that in the
    abstract machine, it has "taken the address" of the constant.

    > However, this is all not so important, unless you work on
    > embedded systems, counting single bytes. What is important
    > that in C++ the const object definitions can legally appear in
    > multiple translation units, without causing linker errors
    > about multiple definitions. Of course, all definitions must be
    > identical. This enables to use such definitions in common
    > header files instead of ancient C macros.


    It can be important for two reasons. The first, of course, is
    if you have header files with lots of such values, say a couple
    hundred, and you end up incorporating the header in many very
    small source files. In such cases, while not likely, it *can*
    end up making a difference. Particularly if those source files
    also have some static variables, which becaue of the extra
    variables end up on separate pages in virtual memory. Program
    size is important today, for reasons of locality. (The number
    of programs affected will be very small, of course.)

    The second is that using the variable in a template may cause
    problems. The template definition will also be included in
    multiple translation units, and according to the standard, there
    will be undefined behavior if the token sequence of the
    definition differs, OR if any name binding differs. In this
    case, the name binding of SomeConst will be different in each
    translation unit, i.e. the symbol SomeConst will refer to a
    different entity in each translation unit. The standard does
    make an exception to this if the symbol is an integral constant
    expression (as it is here), with the same type and initializer
    value everywhere, *and* only if the address of the object is not
    used. (Note that passing the value by reference is using the
    address!)

    [...]
    > > do they wind up in the final executable?


    > Why do you care?


    Locality? Limited memory? (I've worked on systems where the
    entire application had to fit into 64KB, including the OS.)

    > > 2) What about the last two statements with const missing and placed
    > > in a header file


    > > char SomeConst5[] = "A value 3";
    > > char *SomeConst6 = "A value 4";


    > The const you dropped is not the top-level one, so it does not
    > have any significance here.


    In the second line. In the first, it changes the linkage.

    > > At this point, including in 2+ translation units would fall foul of
    > > the one definition rule, right?


    > The same as for SomeConst3 (ok) and SomeConst4 (fails).


    Do you mean that SomeConst3 and SomeConst5 are the same? I
    don't think so.

    Actually, the more I think about it, the less sure I am. In C,
    at least, there is no such thing as a const array, so the const
    isn't top level. G++ treats them as if the arrays themselves
    were const, however (i.e. as if the const were top level).

    > > 3) If I have


    > > const int SomeConst = 1;


    > > in a header file, it is global, is it static or extern by default?


    > This is not the right termonology, the standard speaks about
    > external and internal linkage, etc. I am not sure I can get
    > the details right so I skip that.


    In this case, supposing that the definition is at namespace
    scope, it is internal linkage. But the rules aren't really very
    orthogonal, and can easily lead to confusion.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 25, 2008
    #1
    1. Advertising

  2. James Kanze

    James Kanze Guest

    On May 25, 10:39 pm, Paavo Helde <> wrote:
    > James Kanze <> kirjutas:


    > > On May 24, 10:46 pm, Paavo Helde <> wrote:
    > >> "Stephen Howe" <sjhoweATdialDOTpipexDOTcom> kirjutas:
    > >> > 2) What about the last two statements with const missing and placed
    > >> > in a header file


    > >> > char SomeConst5[] = "A value 3";
    > >> > char *SomeConst6 = "A value 4";


    > >> The const you dropped is not the top-level one, so it does
    > >> not have any significance here.


    > > In the second line. In the first, it changes the linkage.


    > Yes, you are right. I was not prepared to have yet more
    > subtleties, especially such seemingly illogical ones. It's my
    > fault I know, but I cannot understand why should const char
    > array have different linkage than variable char array?
    > Probably something to do with C legacy?


    Well, nothing involving const is due to C legacy, since C++ had
    const before C did. I'm pretty sure that the initial
    modiviation for const affecting linkage is due to things like:

    int const dim = 43 ;

    In C++, `dim' has been a constant integral expression from the
    day const was introduced (where as it is not a constant integral
    expression in C, even today). To work as a constant integral
    expression, of course, you need the initializer. And there are
    a lot of constant integral expressions which you'll want in
    header files as well. If the linkage of the above were external
    (as it is in C, or without the const), you'd have to write:

    static int const dim = 43 ;

    if you wanted to avoid duplicate definitions. And while
    personally, that doesn't bother me, apparently, it did bother
    some early users, and the rule was made (very early) that const
    variables default to internal linkage (i.e. as if they were
    declared static).

    All of this was long before templates, of course, so the fact
    that you cannot use the address of dim as a template argument
    wasn't considered, nor the fact that passing dim by reference in
    a function template results in undefined behavior.

    > OK, I can see some logic here, if the arrays are considered to
    > be extension of a single object to case N>1, then it makes
    > sense that extension of const/non-const object shares the same
    > linkage as the single object. However, in almost all other
    > contexts the array is equivalent to a pointer to a object - I
    > think this is the source of my confusion.


    An array is never really equivalent to a ponter to an object.
    It converts to a pointer to the first element in some specific
    cases, in expressions, but there is still a conversion involved.
    A pointer designates an object; it is NOT that object, nor does
    it contain that object. An array contains its members, and is
    actually more like a struct than a pointer.

    The fact remains that in:
    int const array[ N ] ;
    it is the "int" that is const, and not the array, so the const
    isn't top level, and that at least in C, "If the specification
    of an array type includes any type qualifiers, the element type
    is so qualified, not the array type." So even if you write:
    typedef int A[ N ] ;
    A const array ;
    at least in C, it is not a top level const (not that this makes
    a difference in C). So strictly speaking, I don't think that
    the array definition has top level const, according to the
    standard. On the other hand, at least three compilers (Sun CC,
    g++ and VC++) treat it as if it does.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 26, 2008
    #2
    1. Advertising

  3. James Kanze

    James Kanze Guest

    On May 26, 6:28 am, "Alf P. Steinbach" <> wrote:
    > * Paavo Helde:
    > >> On May 24, 10:46 pm, Paavo Helde <> wrote:
    > >>> "Stephen Howe" <sjhoweATdialDOTpipexDOTcom> kirjutas:
    > >>>> 2) What about the last two statements with const missing and placed
    > >>>> in a header file
    > >>>> char SomeConst5[] = "A value 3";
    > >>>> char *SomeConst6 = "A value 4";
    > >>> The const you dropped is not the top-level one, so it does not
    > >>> have any significance here.
    > >> In the second line. In the first, it changes the linkage.


    > > Yes, you are right. I was not prepared to have yet more
    > > subtleties, especially such seemingly illogical ones. It's
    > > my fault I know, but I cannot understand why should const
    > > char array have different linkage than variable char array?
    > > Probably something to do with C legacy?


    > The two declarations shown above do not have top-level const.
    > They provide assignable variables. Since they're assignable
    > variables, not 'const', they have external linkage by default.


    The real question here is:
    char const SomeConst[] = "A value" ;
    Does SomeConst have external linkage, or internal? Intuitively,
    I would say internal (and g++, Sun CC and VC++ agree with me),
    but I can't find anything in the standard to back this up. And
    if this has internal linkage, how is it different from:
    struct Toto
    {
    int const i ;
    } ;
    Toto x = { 43 } ;
    In both cases, we have an agglomerate in which all elements are
    const (but the agglomerate itself is not declared const).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 26, 2008
    #3
  4. James Kanze

    James Kanze Guest

    On May 26, 1:13 pm, "Alf P. Steinbach" <> wrote:
    > * James Kanze:
    > > On May 26, 6:28 am, "Alf P. Steinbach" <> wrote:
    > >> * Paavo Helde:
    > >>>> On May 24, 10:46 pm, Paavo Helde <> wrote:
    > >>>>> "Stephen Howe" <sjhoweATdialDOTpipexDOTcom> kirjutas:
    > >>>>>> 2) What about the last two statements with const missing and placed
    > >>>>>> in a header file
    > >>>>>> char SomeConst5[] = "A value 3";
    > >>>>>> char *SomeConst6 = "A value 4";
    > >>>>> The const you dropped is not the top-level one, so it does not
    > >>>>> have any significance here.
    > >>>> In the second line. In the first, it changes the linkage.


    > >>> Yes, you are right. I was not prepared to have yet more
    > >>> subtleties, especially such seemingly illogical ones. It's
    > >>> my fault I know, but I cannot understand why should const
    > >>> char array have different linkage than variable char array?
    > >>> Probably something to do with C legacy?


    > >> The two declarations shown above do not have top-level const.
    > >> They provide assignable variables. Since they're assignable
    > >> variables, not 'const', they have external linkage by default.


    > > The real question here is:
    > > char const SomeConst[] = "A value" ;
    > > Does SomeConst have external linkage, or internal?


    > Internal.


    > It's const.


    Well, that's what I think it should be, too. But I can't find
    anything in the standard to back it up.

    > > Intuitively,
    > > I would say internal (and g++, Sun CC and VC++ agree with me),
    > > but I can't find anything in the standard to back this up.


    > §3.5/3 would apply if the object, the array, itself was
    > declared const.


    > But here it's seemingly the elements that are const, and
    > seemingly that the array effective constness stems from arrays
    > not being assignable on their own.


    Exactly. In C, the standard says explicitly that there's no
    such thing as a const array. The C++ standard doesn't say that
    in so many words, but it does say that "Any type of the form
    ``cv-qualifier-seq array of N T'' is adjusted to ``array of N
    cv-qualifier-seq T,[ ...]'', which means that even if you write:

    typedef int A[10];
    A const a ;

    The type of a is array of 10 const int, and the const-ness is
    not top level.

    > There is however a non-normative note at the end of §8.3.4/1
    > that attempts to explain this. Presumably what it's meant to
    > explain is that the /intent/ of that paragraph is that
    > cv-qualification of array elements transfer to the array
    > object itself.


    A very feeble attempt, IMHO. But perhaps sufficient if it were
    normative.

    > Anyway, it explicitly says "internal linkage".


    Where?

    > > And
    > > if this has internal linkage, how is it different from:
    > > struct Toto
    > > {
    > > int const i ;
    > > } ;
    > > Toto x = { 43 } ;
    > > In both cases, we have an agglomerate in which all elements are
    > > const (but the agglomerate itself is not declared const).


    > cv-qualification of elements of a struct does not transfer to
    > the struct itself.


    I know, but according to the standard, the same is true of
    arrays. Only more so, because you can't declare an object of
    array type const.

    Anyhow, I think it's all vague enough for me to raise an issue
    with the committee. I'm not sure, but judging from the behavior
    of the compilers I've tested, I think that there is more or less
    a consensus that the const-ness of the array elements *should*
    cause internal linkage (as if the array itself were const); it's
    just a question of making this clear in the wording of the
    standard.

    With regards to the struct above: I rather like the idea that a
    PODS in which all elements are const would cause objects of that
    type to be const as well, but that would definitely be an
    extention, or a change in the language (and it's probably not
    important enough to bother with).

    Only distantly relevant to the current discussion: I don't see
    anything forbidding a union to contain a const object either,
    e.g.:

    union U { int const a; double b ; } ;

    I don't quite see how it could work, however. (Unions are being
    reworked in the current draft, to remove a lot of the
    restrictions. I'm not sure how this affects const elements in
    unions, however.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 27, 2008
    #4
  5. James Kanze

    James Kanze Guest

    On May 27, 11:26 am, "Alf P. Steinbach" <> wrote:
    > * James Kanze:


    > > On May 26, 1:13 pm, "Alf P. Steinbach" <> wrote:


    > >> There is however a non-normative note at the end of §8.3.4/1
    > >> that attempts to explain this. Presumably what it's meant to
    > >> explain is that the /intent/ of that paragraph is that
    > >> cv-qualification of array elements transfer to the array
    > >> object itself.


    > > A very feeble attempt, IMHO. But perhaps sufficient if it were
    > > normative.


    > >> Anyway, it explicitly says "internal linkage".


    > > Where?


    > <q>
    > Note: an "array of N cv-qualifier-seq T" has cv-qualified type;
    > </q>


    > which I (now I see, explained below, probably incorrectly,
    > although opinions differ) read as an attempted explanation
    > that the element CV-qualification is transferred to the array
    > object itself, and continues, emhpasis added


    > <q>
    > such an array has *internal linkage* unless explicitly declared 'extern'
    > (7.1.5.1) and must be initialized as specified in 8.5.
    > </q>


    That'll teach me to only look at the latest draft for such
    things. The second part you quote above has been dropped in the
    latest draft. Which is curious, because of course, the only
    real intention of this that I can see is to ensure internal
    linkage.

    > Of course if it were taken literally it would raise the issue
    > of auto variables with internal linkage.


    Maybe that's why it was dropped. Or more accurately, replaced
    by "see 3.9.3". Which says in its paragraph 2: "Any
    cv-qualifiers applied to an array type affect the array element
    type, not the array type (8.3.4)." And we're back to where we
    started.

    > In the C++0x draft, at least my old version, the latter quoted
    > part is removed, and instead there is a reference to §3.9.3
    > about CV-qualification, where it's made clear that my
    > interpretation above is not the one to be adopted in C++0x,


    Except that "an `array of N cv-qualifier-seq T' has cv-qualified
    type" seems to directly contradict "Any cv-qualifiers applied to
    an array type affect the array element type, not the array
    type". (The contradiction is in the "not the array type".)

    So someone has been doing something, but it still looks like a
    case of the left hand not knowing what the right hand is doing
    to me. And quite frankly, I'd prefer that arrays of const T
    behave as const array of const T. (Actually, I'd prefer that
    const didn't affect the linkage, and that arrays behaved like
    other composite types, i.e. with copy, no implicit conversion to
    pointer, etc., etc. But it's far too late for either of those
    changes.)

    > Current and C++0x
    > §3.9.3/2
    > "Any cv-qualifiers applied to an array type affect the array
    > element type, not the array type (8.3.4)."


    > The change in §8.3.4/1 wording, removal of that part about
    > internal linkage, follows core language Defect Report #112
    > discussion,


    > http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112


    > which touches on the linkage issue but does not resolve it or
    > really discuss it (the only concern is that "volatile" should
    > not result in internal linkage).


    > Hm.


    I see we're finding most of the same passages (although I'd
    missed the DR).

    > [snip]


    > > Anyhow, I think it's all vague enough for me to raise an issue
    > > with the committee. I'm not sure, but judging from the behavior
    > > of the compilers I've tested, I think that there is more or less
    > > a consensus that the const-ness of the array elements *should*
    > > cause internal linkage (as if the array itself were const); it's
    > > just a question of making this clear in the wording of the
    > > standard.


    > I agree, good idea.


    I've done so, but I really miss csc++ for this. The committee
    reflectors seem more adapted to something more concrete, after a
    bit of preliminary discussion.

    Anyway, while I'm not totally happy with the idea that arrays
    behave differently from other composite types (all elements
    const does not imply composite const), arrays behave differently
    from other composite types in so many other ways, and in the
    absence of anyway to declare an array const, I rather think that
    the best (most intuitive) solution is for the cv-qualification
    of the array to be exactly that of the cv-qualification of its
    elements. (It isn't in C, but in practice, in C, it doesn't
    matter, since the const-ness of the array would have no
    practical effects.)

    Anyway, we'll see what comes of it, but in the meantime, I
    wouldn't count on it being any particular way in a given
    compiler. If I think it might matter, I'll explicitly add a
    static or an extern (depending on what I want).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 28, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Farber
    Replies:
    0
    Views:
    445
    Alexander Farber
    Jun 21, 2005
  2. C. J. Clegg
    Replies:
    4
    Views:
    9,809
    C. J. Clegg
    Mar 28, 2006
  3. Replies:
    11
    Views:
    1,088
  4. Javier
    Replies:
    2
    Views:
    544
    James Kanze
    Sep 4, 2007
  5. mlt
    Replies:
    2
    Views:
    815
    Jean-Marc Bourguet
    Jan 31, 2009
Loading...

Share This Page