const or constant?

Discussion in 'C Programming' started by jacob navia, Apr 22, 2014.

  1. jacob navia

    jacob navia Guest

    After reading some of the contrbutions to the "constant strings" thread,
    I think that what is needed is a clarification of the underlying issues.

    There are TWO "uses" of const:

    1) Declaring that a function will not modify its arguments
    2) Declaring that an object resides in ROM (read only memory)

    The first one is tied to a *scope*. It says that within a certain scope,
    no modifications are done to some object. I would propose that we name
    this property "constant" and we would declare:

    char *strchr(constant char *buffer, int searchedChar);

    This means: "The strchr functions receives a buffeer that will NOT be
    modified within the scope of the function". This implies that inner
    scopes are required to maintain this feature. It means also that when we
    exitthe scope where this "constant" declaration is done, the object
    becomes writable again. Hence it is normal that strchr returns a *plain*
    char pointer. "constant" objects can't be returned as constant.

    The second meaning of const is the usual one and it is tied to an
    *object* not a scope. It means that the object can't be modified at
    *any* scope, it is an intrinsic property of the object.

    In my opinion many problems with "const" would disappear if we
    distinguish between these two usages of const.

    Feedback welcome.
    jacob navia, Apr 22, 2014
    1. Advertisements

  2. It's const not constant
    Bill Cunningham, Apr 22, 2014
    1. Advertisements

  3. There's no requirement that a constant of type 2) is in ROM.
    What about a function like

    void foo( int v ) {
    const int d = v;

    Why should be 'd' in ROM? It only makes sure that the compiler
    will get upset when you try to change its value sometime later
    in the function.

    And you also seem to be forgetting that 1) and 2) can be
    combined as in

    const char * const s

    i.e. a pointer that can't be changed to a region of memory
    that also can't be modified.
    I don't see that this has anything to do with scope. The pit-
    fall, I guess, is that e.g.

    const char * s

    doesn't mean that the value of 's' can't be changed (which
    one might assume) but what it points to. I.e., for a func-
    tion declared as

    void bar( const char * s, const int d );

    it is not really obvious for a beginner that the value of
    'd' can't be changed within the function, but that of 's'
    can (but not what 's' points to). It makes more sense when
    one reads it out aloud as "s is a pointer to const char" -
    you need to read it backwards. Reading it backword also

    const char * const s

    makes sense: it's a "constant pointer to const chars".
    Not only is this unfeasible (it would break millions of
    programs) but it doesn't really seem to make anything
    much clearer. For that you would need a different way
    of declaring/defining pointer. If you could write

    * char s; <=> char * s;

    for "pointer to char", and

    * const char s; <=> const char * s;

    for "pointer to constant char", and

    const * char s; <=> char * const char;

    for "constant pointer to char", and, finally

    const * const char s; <=> const char * const s;

    for "constant pointer to const char", then you'd avoid the
    necessity to read it backwards for pointers which, in my
    opinion, is what can be confusing.

    Another idea would be to use the "address of" operator, '&'
    in declarations/definitions instead of '*', which isn't really
    very logical, e.g.

    &char s; <=> char * s';

    would mean "s is the address of a char", i.e. a pointer to a
    char, a would be nicely similar to a simple

    char s;

    Then you'd have

    &const char s; <=> const char * s;


    const &char s; <=> char * const s;

    and, finally

    const &const char s; <=> const char * const s;

    That way it would make a bit more sense since it could be
    read left to right and the '&' seems to be more appropriate
    in this context than the '*'.

    But while you're at it: perhaps you've also an idea how to
    make function pointers more accessible?;-)

    Regards, Jens
    Jens Thoms Toerring, Apr 22, 2014
  4. jacob navia

    James Kuyper Guest

    Correct. It would be more accurate to say that const-qualification of an
    object allows it to reside in ROM; it doesn't mandate it.
    I'm not sure how you concluded that he's forgotten that; his proposal
    would convert that to "constant char * const s". Note that since 'const'
    would now have only the second meaning, it wouldn't have to be in any
    particular position relative to the '*'. It necessarily applies only to
    the object whose identifier is being declared, regardless of position.
    The 'const' qualification within a function declaration has the first
    meaning only within the scope of the identifier being declared. The
    second meaning applies anywhere that an lvalue expression referring to
    object can be found, whether or not the object's identifier is still in
    scope. An unfortunate consequence of this fact is that violation of the
    relevant restriction cannot be made a constraint violation, because the
    information needed to identify it as such might reside in an entirely
    different translation unit. Jacob's proposal does nothing to avoid that
    James Kuyper, Apr 22, 2014
  5. jacob navia

    Walter Banks Guest

    I essentially agree with you on this. It has been a big problem in
    embedded systems where you want to designate that some data
    resides in ROM.

    The second embedded system issue is it is possible to have
    volatile ROM space where the contents is not known at
    compile time but is fixed at run time. An example of this is
    system calibration constants programmed in ROM or
    serial numbers.

    Walter Banks, Apr 22, 2014
  6. That's not well-worded. No C function can modify it's arguments (as you
    know) so const can't be used to mean that. I know it seems fussy, but
    if you are trying to clarify the issues, writing clearly is not a luxury.
    I think "declaring" is the wrong word. Some implementations make take
    the fact that an object is declared "const" as a prompt to try to put it
    in ROM, but all you are actually declaring (in the simplest case) is
    that the name of the object is not a modifiable lvalue expression.

    But here are some other uses of const:

    double cube_root(const double x) { ... }

    const int n_interations = atoi(argv[2]);

    struct atom {
    const char *const name;
    struct property *plist;

    These don't fit into either of your two cases.
    No, it's tied to the lvalue expression. Other lvalue expressions may
    permit the object to be modified in the same scope. That would
    certainly be unusual but, again, you are trying to be clear here.

    Given that I disagree with the dichotomy you've set up, I don't really
    want to comment on the conclusions you draw. All the uses of const in C
    look similar enough to be to be covered by the same keyword.

    Ben Bacarisse, Apr 22, 2014
  7. jacob navia

    jacob navia Guest

    Le 22/04/2014 23:26, Jens Thoms Toerring a écrit :
    Well, ROM is used here as READ ONLY memory.

    For instance I can obtain a ROM under windows by manipulating the page
    properties and declare it read only. Under Unix there are equivalent
    system calls.

    Even if physically they are not part of the ROM (as the addresses in the
    BIOS for instance) they *are* read only.

    Of course, the compiler is free to leave that in RAM. The program should
    consider those objects as read only.
    jacob navia, Apr 22, 2014
  8. jacob navia

    jacob navia Guest

    Le 22/04/2014 23:56, James Kuyper a écrit :
    I just can't parse that, sorry. Can you provide an example?

    My proposal wants to separate the usage of const to denote an
    unmodifiable object, and the usage of cost to say that the object will
    not be modified at the current scope but can be modified later, when it
    is returned to a higher scope. That's all.
    jacob navia, Apr 22, 2014
  9. If you ever start reading for comprehension, you wouldn't make asinine
    comments like this.
    Barry Schwarz, Apr 22, 2014
  10. jacob navia

    jacob navia Guest

    Le 23/04/2014 00:12, Ben Bacarisse a écrit :
    Well, if I pass a pointer (or an array) to a function, that function can
    modify its arguments and const is usually not used with scalar arguments
    since they are const anyway! <they are just copies of the data.

    But yes, in principle you are right.
    In my opinion

    double cube_root(const double x) { ... }

    should be replaced with
    double cube_root(constant double x) { ... }

    meaning that within "cube_root" x will not be modified but outside it it
    can be modified.

    The second example should also be "constant" since a value obtained from
    non constant data is not really const, just constant.
    Can't parse that. Can you provide an example?

    An lvalue expression could be

    *(p+5) = 'a';

    Now what does that mean in this context?
    jacob navia, Apr 23, 2014
  11. jacob navia

    James Kuyper Guest

    I've been told, on this newsgroup, that there exist systems where memory
    can be switched during the run of a program from read/write to
    read-only, and back again. I know nothing of the details about how that
    works - but on a system where such a feature is supported, it may be
    used in this case.
    James Kuyper, Apr 23, 2014
  12. jacob navia

    James Kuyper Guest

    It would be more accurate to say that when a function takes a parameter
    of type "pointer to const T", the function cannot modify the things the
    pointer points at, except by casting away the 'const'.
    It would be more useful to point out that this applies to any "pointer
    to const T", regardless of whether it is a function parameter.
    With those modifications, Jacob has in fact identified an aspect of
    'const' that is distinct from the other aspect (though he described it
    No, you're also declaring that the object's value cannot be modified
    with defined behavior, not even by use of an lvalue that is not
    const-qualified (6.7.3p6)
    That's an example of Jacob's second case (covered by 6.7.3p6)
    That is an example of Jacob's second meaning. It also is an example of
    the same feature that Jacob's first meaning describes, except that it
    occurs outside of a function parameter list.
    James Kuyper, Apr 23, 2014
  13. jacob navia

    David Brown Guest

    There are many ways in which memory can be mostly read-only, but
    sometimes written. On "big" systems, this can be done by changing
    memory mapping permissions via the MMU. On embedded systems, you get
    things like flash memory with values that are unknown at compile time
    (such as serial numbers that are burned in during production, and
    accessed as "const volatile"), flash memory that is re-programmed at
    run-time, and memory that is written during startup or configuration and
    then locked in some way during normal runs.

    In the case of local data, such as "const time_t now = time(NULL);", I
    cannot imagine a system where this would actually be forced read-only.
    In real-world systems, "now" will be either on the stack or in
    registers, and these will never be read-only.
    David Brown, Apr 23, 2014
  14. It's a common shorthand, but it really confuses many people. C's
    argument passing is nice and simple: pass by value, always. I'll still
    say that you "pass a string to strlen" but in a detailed discussion
    about language semantics that's all wrong!
    (that's not an lvalue expression, but I know what you mean -- an lvalue
    expression ('*(p+5)') is being used to modify some objecet.)
    You said:

    "The first one is tied to a *scope*. It says that within a certain
    scope, no modifications are done to some object."

    I was just making a correction. In this silly example:

    static int total_count;

    void show_counters(const int *counter)
    total_count += 1;
    printf("%d %d\n", *counter, total_count);


    the object is modified in the scope of counter. You just made too
    general a remark: no modifications are done to some object using the
    pointer whose target is const qualified, but other lvalue expressions
    may be able to modify it, even in the same scope. Rather that talk
    about scope, I'd say your first form is a restriction on what you can do
    with certain expressions. There is no guarantee that the object pointed
    to won't change in any particular scope.

    The confusion was significant here in that I completely missed what it
    was you were saying. Sorry about that. Thanks to James's remark, I do
    now see the distinction you want to make, though I am not sure you've
    made a string case for enshrining it in a new keyword.

    Presumably, your new 'constant' can also be used to qualify the target
    of a pointer type. That would introduce new possibilities that can't
    easily be written with const. void f(constant int *ip) would not be the
    same as void f(const int *ip).

    Ben Bacarisse, Apr 23, 2014
  15. I can certainly *imagine* it.


    const time_t now = time(NULL);

    any attempt to modify "now", such as:

    *(time_t*)&now = -1;

    has undefined behavior; that can include crashing because that memory
    location has been (temporarily) marked read-only.

    Doing so could be a way for an implementation to detect logical errors.
    In most cases, it's going to be too expensive to be worthwhile, and I'd
    be surprised to see a compiler that actually does this -- but perhaps on
    some (current or future) hardware marking a memory location as read-only
    is very cheap.

    But the discussion was about ROM, a term that usually refers to memory
    that physically cannot be modified (at least not by simply storing a
    value to it).
    Keith Thompson, Apr 23, 2014
  16. I'm not entirely sure what distinction is being made (the person
    making the suggestion is in my killfile), but I think adding a new
    "constant" keyword in addition to the existing "const" would be a
    bad way to express it.

    There's already a great deal of confusion between "const" (meaning
    read-only) and "constant" (meaning, in most cases, evaluated at
    compile time). Adding a "constant" keyword that *also* doesn't
    mean the same thing as the word "constant" as used in the standard
    would just make that worse.

    I offer no opinion on whether there's a useful distinction here,
    worth adding a new keyword. I merely suggest using a different
    Keith Thompson, Apr 23, 2014
  17. jacob navia

    jacob navia Guest

    Le 23/04/2014 17:40, Keith Thompson a écrit :
    At each of the threads I start, Kiki will repeat the same lie.

    What is the purpose of his killfile if he participates to all the
    threads I start?


    To repeat that I am in his killfile of course!

    I could forget that important fact.

    Thanks kiki
    jacob navia, Apr 23, 2014
  18. jacob navia

    Kaz Kylheku Guest

    How does he know whether the person making the suggestion is in his killfile?

    Must be that somehow the person is there, but not the suggestion.

    Ah, but the "X" in "X in my killfile" is normally understood to be a metonymy
    for "X's textual output". Just like "I listen to Bach" actually means "I
    listen to recordings of Bach's works", not that I have a channel into the
    past that lets me listen to the man himself.

    "The Usenet-published written works of that person who made the written
    suggestion in a Usenet article are in my killfile. Err ..., I mean, *what*
    suggestion? Someone made a suggestion?"
    Kaz Kylheku, Apr 23, 2014
  19. jacob navia

    BartC Guest

    (An early computer board I built had a physical toggle switch on one memory
    bank, to inhibit any /write signal and thus completely protect the RAM as
    though it was read-only memory, provided it was powered-up of course. (BTW
    this is a more fool-proof technique than using 'const'!)

    (This was to protect in-memory source code from a program going haywire; I
    couldn't afford disks.)

    That could also be trivially switched (with a couple of mods) from software,
    although some care would be a needed, as an out-of-control program could
    also re-enable the /write signal. In any case, it's not an impossibility to
    take care of through software. I would, however, trust my toggle switch
    rather more...)
    BartC, Apr 23, 2014
  20. jacob navia

    Ian Collins Guest

    That's what C++ constexpr supports. Why invent yet another wheel when
    there is one already there?
    Ian Collins, Apr 23, 2014
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.