const qualifier

Discussion in 'C Programming' started by Marc van Dongen, Jan 22, 2008.

  1. Dear all,


    I'm a bit confused about the use of the const qualifier. I've studied
    the ANSI version of K&R but this does not seem to provide an
    explanation which corresponds to how const may be used (and is used).

    E.g. it seems that (according to gcc) both "const int var" and "int
    const var" are the same. Likewise, "const int *var"and "int const *
    var"seem to mean the same. Writing "int * const **var" seems to mean
    that the "int *" is constant.

    I'd appreciate it if somebody could point me to some (preferably on-
    line) documentation which describes exactly how to use const.

    TIA.

    Marc van Dongen
     
    Marc van Dongen, Jan 22, 2008
    #1
    1. Advertising

  2. "Marc van Dongen" <> wrote in message
    > I'm a bit confused about the use of the const qualifier. I've studied
    > the ANSI version of K&R but this does not seem to provide an
    > explanation which corresponds to how const may be used (and is
    > used).
    >
    > E.g. it seems that (according to gcc) both "const int var" and "int
    > const var" are the same. Likewise, "const int *var"and "int const *
    > var"seem to mean the same. Writing "int * const **var" seems to
    > mean that the "int *" is constant.
    >
    > I'd appreciate it if somebody could point me to some (preferably on-
    > line) documentation which describes exactly how to use const.
    >

    Basically it means "This function does not modify the thing pointed to by
    this pointer"

    eg

    strcpy(char *dest, const char *src)

    dest must be writeable, src need not be - it could point to an area of ROM,
    for instance.

    Unfortunately the keyword is broken. There are no sensible rules on what
    should happen if dest and src overlap, for example. Also, if we've got this

    struct employee
    {
    char *name;
    float salary
    };

    foo(const struct employee *minion)
    {
    strcpy(minion->name, "Fred");
    }

    is legal. The constness only applies to the structure itself.

    Finally we've got this problem

    strstr() should be able to search for a substring in a constant string, of
    course. But also in a string in RAM that you want to modify. So if passed a
    constant it should return a co0nst char *, if a variable a char *, since
    often the reason you want the address of the substring is to modify it.
    There's no way of expressing this in C.

    My advice is to write code without consts, then add them just as often as
    needed to shut the compiler up.

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
     
    Malcolm McLean, Jan 22, 2008
    #2
    1. Advertising

  3. Marc van Dongen <> writes:

    > Dear all,
    >
    >
    > I'm a bit confused about the use of the const qualifier. I've studied
    > the ANSI version of K&R but this does not seem to provide an
    > explanation which corresponds to how const may be used (and is used).
    >
    > E.g. it seems that (according to gcc) both "const int var" and "int
    > const var" are the same.


    They are.

    > Likewise, "const int *var"and "int const *
    > var"seem to mean the same.


    Right
    > Writing "int * const **var" seems to mean
    > that the "int *" is constant.


    Correct.

    > I'd appreciate it if somebody could point me to some (preferably on-
    > line) documentation which describes exactly how to use const.


    const applies to what preceed it. If nothing preceed it, it applies to
    what immediately follows.

    Yours,

    --
    Jean-Marc
     
    Jean-Marc Bourguet, Jan 22, 2008
    #3
  4. On Jan 22, 2:14 pm, "Malcolm McLean" <> wrote:
    > [problem with const]
    >
    > Basically it means "This function does not modify the thing pointed to by
    > this pointer"
    >
    > eg
    >
    > strcpy(char *dest, const char *src)
    > dest must be writeable, src need not be - it could point to an area of ROM,
    > for instance.


    Thanks. I'm aware of this:)

    [problems]

    I'd like to know how to parse a type with const qualifiers in them.
    Regarding the qualifiers as operators, I'd like to know how they bind
    to the ``read-onlyness of the types.'' So int *const ** var means that
    the int * is read-only. Here it is the entire type to the left of the
    const. However, when we write const int *var, it means some part of
    the type to the right is read-only(the int). If I were to write a
    compiler I'd have to know the rules. My question is "What are the
    rules?".

    Regards,


    Marc van Dongen
     
    Marc van Dongen, Jan 22, 2008
    #4
  5. On Jan 22, 2:20 pm, Jean-Marc Bourguet <> wrote:
    > Marc van Dongen <> writes:


    [snip]

    > > I'd appreciate it if somebody could point me to some (preferably on-
    > > line) documentation which describes exactly how to use const.

    >
    > const applies to what preceed it. If nothing preceed it, it applies to
    > what immediately follows.


    Thank you. That seems to be what I figured out by trial and error. Is
    this written down somewhere?

    Regards,


    Marc van Dongen
     
    Marc van Dongen, Jan 22, 2008
    #5
  6. Marc van Dongen

    James Kuyper Guest

    Marc van Dongen wrote:
    > Dear all,
    >
    >
    > I'm a bit confused about the use of the const qualifier. I've studied
    > the ANSI version of K&R but this does not seem to provide an
    > explanation which corresponds to how const may be used (and is used).
    >
    > E.g. it seems that (according to gcc) both "const int var" and "int
    > const var" are the same. Likewise, "const int *var"and "int const *
    > var"seem to mean the same. Writing "int * const **var" seems to mean
    > that the "int *" is constant.


    Qualifiers like 'const', 'volatile', and 'restrict' can be freely mixed
    with type names like int or short or float of struct tm, without
    changing the meaning of the declaration. However, the order of
    qualifiers and '*' does matter. In the declaration;

    int * const cpi

    The 'const' qualifier applies to 'cpi' itself. In the declaration

    int const * pci

    the 'const' qualifier applies to the thing pointed at by pci.

    > I'd appreciate it if somebody could point me to some (preferably on-
    > line) documentation which describes exactly how to use const.


    That is a big, complicated subject, and I don't know of a good online
    tutorial. My summary:

    Declaring something const makes it a constraint violation to attempt to
    modify it. This is a good thing, because implementations are required to
    diagnose constraint violations. If you can defer declaring an object
    until it already has it's initial value, and if you know that the
    initial value should never be changed, then it's a good idea to declare
    it const, because that will ensure that you get diagnostic messages if
    you made a mistake, and your code actually changes the value of the
    object. You might need to fix the code which changes the value, or you
    might need to remove the 'const' qualifier, but the diagnostic is useful
    because it points out to you the conflict between what your code does
    and what you thought it should do.

    You can usually work around the restrictions by using a cast:

    *(int *)pci = 3;

    This is perfectly legitimate in itself (but see below), and there are
    sometimes legitimate reasons for doing so. However, you should
    understand that whenever you use an cast, you're telling the compiler
    "This looks bad, but I know what I'm doing". Always be very sure that
    you do indeed know what you're doing, before using any explicit cast.
    Treat any cast you find in anyone's code, including your own, as a
    danger sign.

    Defining an object to be 'const' is a more complicated issue from simply
    declaring it. The result is that if your code uses the above technique
    to attempt to modify the value of that object, the behavior of your
    program is undefined. The change might simply fail to happen, or your
    program might abort(), but there's a literal infinity of other possible
    behaviors that are generally less likely than those two.

    On some platforms, it's possible for your compiler to lock a piece of
    memory against changes after initializing it. If so, the 'const'
    qualifier on an object definition gives the compiler permission to do
    so. That's an easy way to think about it, and I recommend keeping that
    model in mind. However, even on machines where there's no such
    capability, an implementation is still permitted to generate code based
    upon the assumption that such an object's value will never be changed.
    As a result, arbitrarily bizarre things can happen if that assumption is
    violated. For instance:

    In one part of the code:
    const int i=5;

    In another part of the code:
    int j = 10*sizeof(int);

    Instead of loading an actual value of 10 into a register, a conforming
    implementation could load the current value of 'i' and multiply by 2.
    If you've changed the value of 'i', that will result in an invalid value
    being given to j, despite the fact that there's no obvious connection
    between them. That's an extremely unlikely way of handling such code,
    but it's no less dangerous than other more likely possibilities that are
    harder to explain.
     
    James Kuyper, Jan 22, 2008
    #6
  7. Marc van Dongen <> writes:

    > I'd like to know how to parse a type with const qualifiers in them.
    > Regarding the qualifiers as operators, I'd like to know how they bind
    > to the ``read-onlyness of the types.'' So int *const ** var means that
    > the int * is read-only. Here it is the entire type to the left of the
    > const. However, when we write const int *var, it means some part of
    > the type to the right is read-only(the int). If I were to write a
    > compiler I'd have to know the rules. My question is "What are the
    > rules?".


    The rules are in the formal syntax. This does not really help except
    to act as the final arbiter. The syntax is messy enough that hand
    parsing is tedious. So, just like the syntax for expressions has been
    synthesised into a precedence table, the type syntax rules have been
    synthesised into various "rules of thumb".

    What I used to tell students was:

    Re-write so you have only one "thing" being declared/defined, then put
    your finger on the name (or where the name would be) and read out the
    name followed by the symbols using these rules:

    * Always read to the left first but never past a ')'.

    * Then read to the right.

    * If you hit the start you are done.

    * If you hit a '(' remove everything in the matching '(...)' pair
    and start again reading to the left.

    As you do this voice the symbols like this:

    '*' "pointer to"

    '[' "array of" then read what is inside the '[]'

    '(' "function taking" and then read using these rules each of the
    parameter types (you need to jump to find the where the name
    is or would be in each one). For '(void)' just say "no
    parameters", and for '()' say "unspecified parameters".
    Follow this with "and which returns" and keep going.

    '...' "further var-args" (you can re-word this if it too much like
    Vogon poetry for you).

    You have to add in a few extra words to make real sentences but the
    basic idea of going from the inside out and to the left first is a
    basic consequence of the formal syntax of the language.

    Unfortunately this is not 100% "culture fair" since it relies on a
    property of English that "int const" and "const int" probably indicate
    the same thing. I have found some people really bothered by this and
    they are usually non-native English speakers.

    If fails for function parameters of the form 'x[..]'. You can update
    the rules to take these into account but it is a bit messy.

    A couple of examples:

    const struct node *f(void);
    ^
    start here

    "f is a function taking no parameters and which returns a node
    struct const."

    int (*list_op)(const struct node *);

    "list_op is a pointer to a function taking a pointer to a node
    struct const and which returns an int."

    --
    Ben.
     
    Ben Bacarisse, Jan 22, 2008
    #7
  8. Marc van Dongen

    Guest

    James Kuyper wrote:
    ....
    > Qualifiers like 'const', 'volatile', and 'restrict' can be freely mixed
    > with type names like int or short or float of struct tm, without


    "mixed" was the wrong term. What I meant is that they can freely be
    reordered with respect to each other.
     
    , Jan 22, 2008
    #8
    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. Sergey Tolstov

    const qualifier and VC6.0

    Sergey Tolstov, Oct 7, 2003, in forum: C++
    Replies:
    8
    Views:
    490
    Howard
    Oct 7, 2003
  2. Mahesh Tomar

    Const Qualifier question

    Mahesh Tomar, Sep 1, 2004, in forum: C++
    Replies:
    4
    Views:
    378
    Old Wolf
    Sep 2, 2004
  3. Patrick Guio

    const qualifier problem

    Patrick Guio, Nov 9, 2004, in forum: C++
    Replies:
    5
    Views:
    336
    Vyacheslav Kononenko
    Nov 9, 2004
  4. Javier
    Replies:
    2
    Views:
    605
    James Kanze
    Sep 4, 2007
  5. paulo
    Replies:
    9
    Views:
    734
    James Kanze
    Mar 6, 2009
Loading...

Share This Page