Using const qualifier

Discussion in 'C Programming' started by amvoiepd@hushmail.com, Dec 30, 2007.

  1. Guest

    Hi,
    My question is about how to use const properly.
    I have two examples describing my problem.

    First, let's say I have a linked list and from it I want to
    find some special node. I write the function, and then figure
    that the function will not be modifying the list at all, so a
    const qualifier seems appropriate in the parameter.
    So essentially I have:

    struct node {
    ...
    struct node *next;
    };

    struct node *find_special(const struct node *n)
    {
    while (...) {
    ...
    n = n->next;
    ....
    }
    return n;
    }

    But this will give me a warning since I am returning n,
    which is declared const, and my function is not returning
    a const. How do I fix this? If I change my function to
    return a const, I would be stuck with a variable which I can
    not change when I use my function, right?

    Also, let's say I have a function that assigns a pointer to a
    member of a struct. Here I also think a const would do:

    void assign_pointer(struct mystruct *s, const int *p)
    {
    s->pointer = p;
    }

    struct mystruct {
    int *pointer;
    };

    Same problem here, I'm assigning a const to a non const.
    What to do? I can't add const to my struct member, since
    I want to do things with it later.

    So how do I use const properly? I do understand the reason
    why these examples fail, just not how to handle it.

    Thanks!
    , Dec 30, 2007
    #1
    1. Advertising

  2. wrote:
    > Hi,
    > My question is about how to use const properly.
    > I have two examples describing my problem.
    >
    > First, let's say I have a linked list and from it I want to
    > find some special node. I write the function, and then figure
    > that the function will not be modifying the list at all, so a
    > const qualifier seems appropriate in the parameter.
    > So essentially I have:
    >
    > struct node {
    >     ...
    >     struct node *next;
    > };
    >
    > struct node *find_special(const struct node *n)
    > {
    >     while (...) {
    >         ...
    >         n = n->next;
    >         ....
    >     }
    >     return n;
    > }
    >
    > But this will give me a warning since I am returning n,
    > which is declared const, and my function is not returning
    > a const. How do I fix this?


    Cast the return value to non-const.

    > If I change my function to
    > return a const, I would be stuck with a variable which I can
    > not change when I use my function, right?


    Yes.

    > Also, let's say I have a function that assigns a pointer to a
    > member of a struct. Here I also think a const would do:
    >
    > void assign_pointer(struct mystruct *s, const int *p)


    This would only be a valid design if 's->pointer' is also const.
    If it isn't (and isn't meant to be) remove the const
    qualifier against *p.

    > {
    >     s->pointer = p;
    > }
    >
    > struct mystruct {
    >     int *pointer;
    > };


    --
    Peter
    Peter Nilsson, Dec 30, 2007
    #2
    1. Advertising

  3. Guest

    On Dec 30, 2:11 am, Peter Nilsson <> wrote:
    > wrote:
    > > Hi,
    > > My question is about how to useconstproperly.
    > > I have two examples describing my problem.

    >
    > > First, let's say I have a linked list and from it I want to
    > > find some special node. I write the function, and then figure
    > > that the function will not be modifying the list at all, so a
    > >constqualifierseems appropriate in the parameter.
    > > So essentially I have:

    >
    > > struct node {
    > > ...
    > > struct node *next;
    > > };

    >
    > > struct node *find_special(conststruct node *n)
    > > {
    > > while (...) {
    > > ...
    > > n = n->next;
    > > ....
    > > }
    > > return n;
    > > }

    >
    > > But this will give me a warning since I am returning n,
    > > which is declaredconst, and my function is not returning
    > > aconst. How do I fix this?

    >
    > Cast the return value to non-const.


    I knew that was one possible way to silence the warning, but
    having read this groups for some time, I had the impression that
    casts are almost never necessary. Is this a case where a cast
    is perfectly okay?

    > > If I change my function to
    > > return aconst, I would be stuck with a variable which I can
    > > not change when I use my function, right?

    >
    > Yes.
    >
    > > Also, let's say I have a function that assigns a pointer to a
    > > member of a struct. Here I also think aconstwould do:

    >
    > > void assign_pointer(struct mystruct *s,constint *p)

    >
    > This would only be a valid design if 's->pointer' is alsoconst.
    > If it isn't (and isn't meant to be) remove theconstqualifieragainst *p.


    What makes the first example a valid design, but not this one if 's-
    >pointer'

    is not const? I mean, in respective function the pointers are not
    altered
    at all, but after the function ends they can be altered. I don't see
    the
    difference between them. Does a function need to take into account
    that a
    pointer may be changed after returning from a function?

    > > {
    > > s->pointer = p;
    > > }

    >
    > > struct mystruct {
    > > int *pointer;
    > > };

    >
    > --
    > Peter


    Thanks!
    , Dec 30, 2007
    #3
  4. Eric Sosman Guest

    wrote:
    > On Dec 30, 2:11 am, Peter Nilsson <> wrote:
    >> wrote:
    >>> [... function deriving non-const value from const argument ...]
    >>> But this will give me a warning since I am returning n,
    >>> which is declaredconst, and my function is not returning
    >>> aconst. How do I fix this?

    >> Cast the return value to non-const.

    >
    > I knew that was one possible way to silence the warning, but
    > having read this groups for some time, I had the impression that
    > casts are almost never necessary. Is this a case where a cast
    > is perfectly okay?


    Yes, I'd say so. C's system of types is not very
    flexible, and the type qualifiers like const can become
    inconvenient at times, providing useful documentation for
    a parameter at the cost of "poisoning" other expressions.
    Cast it away.

    As for "casts are almost never necessary," I think
    that's a misstatement of "most casts are misused." The
    latter isn't a statement about casts, really, but about
    the programmers who misuse them -- and whose numbers are
    legion. In English, "comprise" is almost always wrong
    not because there's anything amiss with the word, but
    because it is nearly always misused. If you can use
    "comprise" correctly you are in a minority; a similar
    situation seems to hold with casts.

    --
    Eric Sosman
    lid
    Eric Sosman, Dec 30, 2007
    #4
  5. Guest

    On 30 Dec, 00:42, wrote:
    > Hi,
    > My question is about how to use const properly.
    > I have two examples describing my problem.


    What Peter and Eric have said elsethread is correct, but I think your
    conception may be wrong.

    > First, let's say I have a linked list and from it I want to
    > find some special node. I write the function, and then figure
    > that the function will not be modifying the list at all, so a
    > const qualifier seems appropriate in the parameter.
    > So essentially I have:
    >
    > struct node {
    >     ...
    >     struct node *next;
    >
    > };
    >
    > struct node *find_special(const struct node *n)
    > {
    >     while (...) {
    >         ...
    >         n = n->next;
    >         ....
    >     }
    >     return n;
    >
    > }


    This function returns a non-const pointer to a node of the list. The
    function itself does not modify the list. But it returns a pointer
    through which you could modify the list. So your function, having
    promised not to modify the list, can't then guarantee that the promise
    is kept. This is why you are having problems.

    > Also, let's say I have a function that assigns a pointer to a
    > member of a struct. Here I also think a const would do:
    >
    > void assign_pointer(struct mystruct *s, const int *p)
    > {
    >     s->pointer = p;
    >
    > }
    >
    > struct mystruct {
    >     int *pointer;
    >
    > };


    Similar problem here. Your function promises that it won't alter the
    int that p points to. But it lets "pointer" point to it, and "pointer"
    is free to alter the value pointed at.

    I think you need to ask yourself the question "Do I want the pointed-
    at thing to be alterable, or not?" and arrange your consts
    accordingly.

    Hope that helps.
    Paul.
    , Dec 30, 2007
    #5
  6. Chris Torek Guest

    In article <>
    <> wrote:
    >[The node-finding] function returns a non-const pointer to a
    >node of the list. The function itself does not modify the list.
    >But it returns a pointer through which you could modify the list.
    >So your function, having promised not to modify the list, can't
    >then guarantee that the promise is kept. This is why you are
    >having problems.


    Indeed: given a function that does not modify the object or objects
    to which its argument pointer(s) point, but *does* return a pointer
    to one of those objects, you have a problem.

    Do you use "const" to imply "I will not change this, and thus you
    can pass to me a pointer to an actually-const, really-in-ROM object",
    and then have the return value "de-const-ified"? In which case,
    you can do bad things:

    typedef <whatever> T;
    T *deconstify(const T *);
    const T read_only_obj = { value_that_cannot_change };
    *deconstify(&read_only_obj) = oops_a_bug;

    Or, do you avoid const, after which you cannot even *call* the
    function even though you would have done it safely? For instance:

    T *nonconst(T *); /* nonconst() does not modify it though */
    const T *ptr;
    ptr = nonconst(&read_only_obj); /* alas, this gets a diagnostic */

    The Standard C Library takes the former approach: functions like
    strchr() "deconstify" their argument:

    const char ro[] = "room!";

    *strchr(ro, 'r') = 'b'; /* boom! */

    (which may indeed "go boom", i.e., crash, and does on some of my
    systems).

    One of the many reasons C++ has overloaded functions is to sidestep
    this problem. In C++, the types of arguments -- including whether
    they are const-qualified -- determine which function is actually
    called, so we simply write two completely separate functions:

    const int *operate(const int *);
    int *operate(int *);

    Then:

    const int obj1 = 0
    int obj2 = 0;

    *operate(&obj1) = 42;

    will not compile, because &obj1 has type "const int *", so this
    calls operate(const int *), which returns "const int *", not
    "int *". Of course, this opens the door to abuse: the two
    separate functions might well do entirely different things.
    Ideally, the const-qualified version of the function does the
    same thing as the non-const-qualified version, and in a language
    better than C++, we could avoid writing two functions by simply
    declaring that the return type matches the argument type:

    flexible operate(arg) [
    constraint: typeof(operate) is typeof(arg);
    constraint: typeof(arg) is choice { int *, const int * };
    ] {
    ...
    return arg;
    }

    which also of course lets us write "overloaded" functions without
    repeating them six ways from Sunday:

    /*
    * Substring operation: find "needle" in "haystack"
    */
    flexible substring(haystack, needle) [
    constraint: typeof(operate) is typeof(haystack);
    constraint: typeof(needle) is typeof(haystack);
    constraint: typeof(haystack) is choice {
    char *, const char *,
    Unicode16 *, const Unicode16 *,
    Unicode32 *, const Unicode32 *
    };
    ] {
    ... code to find substring ...
    }

    (To achieve the above, C++ generally uses "templates" instead of,
    or combined with, "overloaded" functions, but there is really
    no need for both.)

    (I made up the above syntax on the fly, so it is probably full
    of flaws.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Dec 30, 2007
    #6
  7. Army1987 Guest

    Chris Torek wrote:

    [snip]
    > Ideally, the const-qualified version of the function does the
    > same thing as the non-const-qualified version, and in a language
    > better than C++, we could avoid writing two functions by simply
    > declaring that the return type matches the argument type:

    [snip]
    > which also of course lets us write "overloaded" functions without
    > repeating them six ways from Sunday:
    >
    > /*
    > * Substring operation: find "needle" in "haystack"
    > */
    > flexible substring(haystack, needle) [
    > constraint: typeof(operate) is typeof(haystack);
    > constraint: typeof(needle) is typeof(haystack);

    Why? What's wrong with allowing substring(L"unicode string", "string")?
    > constraint: typeof(haystack) is choice {
    > char *, const char *,
    > Unicode16 *, const Unicode16 *,
    > Unicode32 *, const Unicode32 *
    > };
    > ] {
    > ... code to find substring ...
    > }


    --
    Army1987 (Replace "NOSPAM" with "email")
    Army1987, Jan 2, 2008
    #7
    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:
    463
    Howard
    Oct 7, 2003
  2. Mahesh Tomar

    Const Qualifier question

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

    const qualifier problem

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

Share This Page