Whats the deal with 'const'?

Discussion in 'C Programming' started by Snis Pilbor, Jul 15, 2006.

  1. Snis Pilbor

    Snis Pilbor Guest

    Whats the point of making functions which take arguments of a form like
    "const char *x"? It appears that this has no effect on the function
    actually working and doing its job, ie, if the function doesn't write
    to x, then it doesnt seem like the compiler could care less whether I
    specify the const part. Quite the opposite, if one uses const
    liberally and then later goes back and changes the functions, headaches
    will inevitably occur as one tries to compile and the compiler gripes
    because now suddenly you ARE writing to x, so you have to go back and
    remove the const keyword, and this might mean painstakingly removing it
    from dozens of lines if the function in question is deeply nested
    amidst a family of functions that call eachother and all have 'const'
    keywords.

    Is const, in this context (ie passing const arguments to functions)....

    1. A Java-like "babysitter" keyword based on the premise that all
    programmers are idiots and must have their hands held at all times?
    2. Used to alert the compiler that some kind of extra optimization is
    possible, which wouldn't be possible if the data in question were
    manipulated? And if so, exactly what sort of optimization would this
    be?
    3. About as useful as a comment, with no other purpose but as a little
    yellow sticky note saying "this function should act nondestructively on
    this particular thing"?

    I always assumed it was some combination of 1 and 3 and so I tend to
    never, ever use the thing...

    Thanks, this is something I've always been curious about =)

    Snis Pilbor
     
    Snis Pilbor, Jul 15, 2006
    #1
    1. Advertising

  2. Snis Pilbor posted:

    > Whats the point of making functions which take arguments of a form like
    > "const char *x"?



    (Just for sake of pedantry:)

    This is a non-const pointer variable which points to a const char.


    > It appears that this has no effect on the function
    > actually working and doing its job, ie, if the function doesn't write
    > to x, then it doesnt seem like the compiler could care less whether I
    > specify the const part.



    The calling function cares:


    void Func(char*);

    int main(void)
    {
    char const c = 0;

    Func(&c); /* Compiler ERROR */
    }


    > Quite the opposite, if one uses const
    > liberally and then later goes back and changes the functions, headaches
    > will inevitably occur as one tries to compile and the compiler gripes
    > because now suddenly you ARE writing to x, so you have to go back and
    > remove the const keyword, and this might mean painstakingly removing it
    > from dozens of lines if the function in question is deeply nested
    > amidst a family of functions that call eachother and all have 'const'
    > keywords.



    Revising whether a function alters its argument changes the very nature of
    the function!

    I take it you're new to "const"? "const" is brilliant.

    Use it (almost) everywhere you can and you'll be left with very robust
    code.


    > 1. A Java-like "babysitter" keyword based on the premise that all
    > programmers are idiots and must have their hands held at all times?



    I would consider "const" to have two main purposes:

    (1) To aid in optimisation.
    (2) To make code fail to compile if "constness" is violated.


    <OFF-TOPIC>

    Using function overloading in C++, you can write two totally different
    functions -- one which alters its argument, and one which doesn't:

    void Func(int *p);

    void Func(int const *p);

    </OFF-TOPIC>


    > 2. Used to alert the compiler that some kind of extra optimization is
    > possible, which wouldn't be possible if the data in question were
    > manipulated? And if so, exactly what sort of optimization would this
    > be?



    Consider:

    int Func(int const x)
    {
    return x + 5;
    }

    Maybe the compiler will re-use the argument variable... ?


    > 3. About as useful as a comment, with no other purpose but as a little
    > yellow sticky note saying "this function should act nondestructively on
    > this particular thing"?



    It is reliable as such an indicator.


    Don't forget:

    It's undefined behaviour to alter a const object.


    --

    Frederick Gotham
     
    Frederick Gotham, Jul 15, 2006
    #2
    1. Advertising

  3. Snis Pilbor

    aragonsr Guest

    It helps with debugging. Putting const in the prototype allows you to 1)
    send a "const" variable to the function or a nonconst variable to the
    function. Without the const keyword, you could only send a nonconst variable
    to the function. 2) when using references and pointers, it prevents the
    function from modifying it which allows you to isolate bugs.

    Although I believe references have to do with cpp, here is something that
    you might find useful. Take this definition for example:

    void object::func( const int* const variable ) const { ; }

    the first const prevents the pointer from be moved around ( pointer
    arithmetic ), the second const prevents the data to which the pointer points
    to from being manipulated, and the third const prevents the function from
    modifying member variables that belong to the class "object". The third one
    is a cpp feature, but the other two should still hold true for C. Although I
    believe the keyword "const" is a cpp keyword anyways and not a C keyword.
    There is some ambituity there too I believe but I'm not sure.

    I doubt there is any optimization, I don't know exactly what the compiler
    produces when it comes to the const keyword so I don't know.



    "Snis Pilbor" <> wrote in message
    news:...
    > Whats the point of making functions which take arguments of a form like
    > "const char *x"? It appears that this has no effect on the function
    > actually working and doing its job, ie, if the function doesn't write
    > to x, then it doesnt seem like the compiler could care less whether I
    > specify the const part. Quite the opposite, if one uses const
    > liberally and then later goes back and changes the functions, headaches
    > will inevitably occur as one tries to compile and the compiler gripes
    > because now suddenly you ARE writing to x, so you have to go back and
    > remove the const keyword, and this might mean painstakingly removing it
    > from dozens of lines if the function in question is deeply nested
    > amidst a family of functions that call eachother and all have 'const'
    > keywords.
    >
    > Is const, in this context (ie passing const arguments to functions)....
    >
    > 1. A Java-like "babysitter" keyword based on the premise that all
    > programmers are idiots and must have their hands held at all times?
    > 2. Used to alert the compiler that some kind of extra optimization is
    > possible, which wouldn't be possible if the data in question were
    > manipulated? And if so, exactly what sort of optimization would this
    > be?
    > 3. About as useful as a comment, with no other purpose but as a little
    > yellow sticky note saying "this function should act nondestructively on
    > this particular thing"?
    >
    > I always assumed it was some combination of 1 and 3 and so I tend to
    > never, ever use the thing...
    >
    > Thanks, this is something I've always been curious about =)
    >
    > Snis Pilbor
    >
     
    aragonsr, Jul 15, 2006
    #3
  4. aragonsr posted:


    > void object::func( const int* const variable ) const { ; }
    >
    > the first const prevents the pointer from be moved around ( pointer
    > arithmetic ),



    The first const prevents alteration of the data which is pointed to.


    > the second const prevents the data to which the pointer
    > points to from being manipulated,



    The second const prevents alteration of the pointer variable itself.


    > I doubt there is any optimization, I don't know exactly what the
    > compiler produces when it comes to the const keyword so I don't know.



    It's very likely to change:

    unsigned const len = 5;

    unsigned i = len;


    into simply:


    unsigned i = 5;


    This would have an optimising effect on the resultant machine code, as,
    rather than accessing "len" and subsequently loading a register with its
    value, it would use a CPU instruction whereby it can pass 5 directly.


    --

    Frederick Gotham
     
    Frederick Gotham, Jul 15, 2006
    #4
  5. Snis Pilbor

    Jack Klein Guest

    On 15 Jul 2006 09:34:40 -0700, "Snis Pilbor" <>
    wrote in comp.lang.c:

    > Whats the point of making functions which take arguments of a form like
    > "const char *x"? It appears that this has no effect on the function
    > actually working and doing its job, ie, if the function doesn't write
    > to x, then it doesnt seem like the compiler could care less whether I
    > specify the const part. Quite the opposite, if one uses const
    > liberally and then later goes back and changes the functions, headaches
    > will inevitably occur as one tries to compile and the compiler gripes
    > because now suddenly you ARE writing to x, so you have to go back and
    > remove the const keyword, and this might mean painstakingly removing it
    > from dozens of lines if the function in question is deeply nested
    > amidst a family of functions that call eachother and all have 'const'
    > keywords.


    The definition of a function parameter as "const char *x" defines that
    argument as a pointer to one or more constant characters. The pointer
    may be changed, any characters that it points to may not. This means
    it may be called with a pointer to constant or non constant
    characters. It is also a promise by the implementer of the function
    that it will not attempt to modify any character(s) pointed to by 'x'.

    Given a prototype of a function that accepts a pointer to const char,
    a programmer may call that function with a pointer to one or more
    chars that may not be modified, either an actual constant char or
    array of constant chars, or a string literal.

    Or it may be that the data pointed to is not a literal or constant,
    but the caller needs it to keep its present value for further
    processing.

    > Is const, in this context (ie passing const arguments to functions)....
    >
    > 1. A Java-like "babysitter" keyword based on the premise that all
    > programmers are idiots and must have their hands held at all times?


    Making an object parameter constant is something like babysitting.
    Some pedants here seem to like it, but it is only for the use of the
    programmer writing the function. Example:

    int some_func(const int x)
    {
    /* body */
    }

    The programmer is expressing his intent not to change the value of the
    int parameter 'x' inside the function, and is instructing the compiler
    to warn him if he does so. It is not part of the function's
    interface, and completely useless information to a caller of the
    function, because the 'x' the function receives is a copy of the
    caller's value, and changes made to it inside this function cannot
    have any effect on any object in the caller.

    Some people like this because it prevents a certain type of error,
    namely when an argument is modified early in a function when code
    later in a function expects it to retain the original value.

    My response to that would be that if a function is long or complex
    enough that such a mistake is easy to make and easy to overlook, the
    function should be split into two or more smaller, simpler functions.

    > 2. Used to alert the compiler that some kind of extra optimization is
    > possible, which wouldn't be possible if the data in question were
    > manipulated? And if so, exactly what sort of optimization would this
    > be?


    The C standard does not define optimizations. There might well be
    optimizations possible with data pointed to by a pointer to const, but
    that is an implementation detail and off-topic here.

    > 3. About as useful as a comment, with no other purpose but as a little
    > yellow sticky note saying "this function should act nondestructively on
    > this particular thing"?


    No, it is far, far more useful than a comment, at least when talking
    about pointers to const objects. Especially when used properly.

    > I always assumed it was some combination of 1 and 3 and so I tend to
    > never, ever use the thing...
    >
    > Thanks, this is something I've always been curious about =)


    Consider:

    int my_strlen1(const char *x)
    {
    int count = 0;
    while (*x)
    {
    ++count;
    ++x;
    }
    return count;
    }

    int my_strlen2(char *x)
    {
    int count = 0;
    while (*x)
    {
    ++count;
    ++x;
    }
    return count;
    }

    int main(void)
    {
    const char *str = "Hello, World!";
    int l1 = my_strlen1(str);
    int l2 = my_strlen2(str);
    puts(str);
    return 0;
    }

    Your compiler should issue a diagnostic when you attempt to call
    my_strlen2 with a pointer to const. And that's important, because the
    pointer 'str' points to a string literal, and modifying a string
    literal produces undefined behavior.

    If you modify my_strlen1, say like this:

    int my_strlen1(const char *x)
    {
    int count = 0;
    while (*x)
    {
    ++count;
    *x = '?';
    ++x;
    }
    return count;
    }

    ....the compiler will issue a diagnostic. To remove the diagnostic you
    must remove the const qualifier. If your code is organized properly,
    that is the same prototype is in scope at the definition and all calls
    to a function, removing the const qualifier from the prototype will
    cause a diagnostic when the caller sends a pointer to a string literal
    to the function. And this is a good thing, because passing a string
    literal to a function that attempts to modify it is a serious error
    and causes undefined behavior.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Jul 15, 2006
    #5
  6. Snis Pilbor

    Snis Pilbor Guest

    Frederick Gotham wrote:
    > Snis Pilbor posted:
    > (snip)
    >
    > > Quite the opposite, if one uses const
    > > liberally and then later goes back and changes the functions, headaches
    > > will inevitably occur as one tries to compile and the compiler gripes
    > > because now suddenly you ARE writing to x, so you have to go back and
    > > remove the const keyword, and this might mean painstakingly removing it
    > > from dozens of lines if the function in question is deeply nested
    > > amidst a family of functions that call eachother and all have 'const'
    > > keywords.

    >
    >
    > Revising whether a function alters its argument changes the very nature of
    > the function!
    > (snip)


    Not to be argumentative, but consider the following two versions of the
    same function:

    void print_first_5( char *x )
    {
    char buf[6];
    int i;

    for ( i = 0; i < 5; i++ )
    buf = x;

    buf[5] = '\0';
    printf( buf );
    }

    void print_first_5( char *x )
    {
    char tmp;

    tmp = x[5];
    x[5] = '\0';
    printf( x );
    x[5] = tmp;
    }

    As far as I can tell, the 2nd is both faster and takes less memory.
    The two do the exact same thing, assuming that printf itself acts
    nondestructively. If I used const to tell the compiler that
    print_first_5 acts nondestructively on x in the 2nd version, the
    compiler would think I was mistaken even though I'm correct. The point
    is, the change can hardly be said to "change the very nature of this
    function", and if this were deeply nested in a family of functions
    using const arguments, a massive headache would arise.

    S.P.
     
    Snis Pilbor, Jul 15, 2006
    #6
  7. Jack Klein posted:


    >> 2. Used to alert the compiler that some kind of extra optimization is
    >> possible, which wouldn't be possible if the data in question were
    >> manipulated? And if so, exactly what sort of optimization would this
    >> be?

    >
    > The C standard does not define optimizations. There might well be
    > optimizations possible with data pointed to by a pointer to const, but
    > that is an implementation detail and off-topic here.



    Yes, that must be the exact reason why we have a "register" keyword.

    I suppose "inline" has nothing to do with optimisation either.


    --

    Frederick Gotham
     
    Frederick Gotham, Jul 15, 2006
    #7
  8. Snis Pilbor posted:

    > Not to be argumentative, but consider the following two versions of the
    > same function:
    >
    > void print_first_5( char *x )
    > {
    > char buf[6];
    > int i;
    >
    > for ( i = 0; i < 5; i++ )
    > buf = x;
    >
    > buf[5] = '\0';
    > printf( buf );
    > }



    #include <stdio.h>
    #include <string.h>

    void PrintFirst5(char const *p)
    {
    char static buf[5+1]; /* Auto null terminator */

    memcpy(buf,p,5);

    puts(buf);
    }


    > void print_first_5( char *x )
    > {
    > char tmp;
    >
    > tmp = x[5];
    > x[5] = '\0';
    > printf( x );
    > x[5] = tmp;
    > }



    #include <stdio.h>
    #include <string.h>

    void PrintFirst5(char *p)
    {
    char * const register p_last = p + 5;

    char const tmp = *p_last;

    *p_last = 0;

    puts(p);

    *p_last = tmp;
    }


    > As far as I can tell, the 2nd is both faster and takes less memory.



    Indeed, however the array which it accesses must be non-const.

    Consider:

    PrintFirst5("carpenter");


    > If I used const to tell the compiler that
    > print_first_5 acts nondestructively on x in the 2nd version, the
    > compiler would think I was mistaken even though I'm correct.



    You are mistaken.

    You alter the data. Just because you later restore it to its original state
    doesn't mean there was no alteration in the first place.

    By your logic, if I was caught shoplifting, I could say "I was only
    borrowing it, and was going to restore it to its original position before
    anyone noticed".


    > The point is, the change can hardly be said to "change the very nature
    > of this function", and if this were deeply nested in a family of
    > functions using const arguments, a massive headache would arise.



    The second form of the function is "clever".

    You have changed the way the function works.

    Perhaps the most fundamental aspect of a function, and the aspect which
    should be documented clearly, is "whether it alters its arguments".

    <OFF-TOPIC>

    In C++, you could get the best of both worlds by using function overloading
    to supply two functions: one which can work with const data, and one which
    is optimised to work with non-const data.

    </OFF-TOPIC>


    Get the hang of using "const" and you'll realise it's the best thing since
    sliced bread.


    --

    Frederick Gotham
     
    Frederick Gotham, Jul 15, 2006
    #8
  9. Frederick Gotham posted:


    > #include <stdio.h>
    > #include <string.h>
    >
    > void PrintFirst5(char const *p)
    > {
    > char static buf[5+1]; /* Auto null terminator */
    >
    > memcpy(buf,p,5);
    >
    > puts(buf);
    > }



    I should have written the function parameter as:

    char const * const p



    > void PrintFirst5(char *p)
    > {
    > char * const register p_last = p + 5;
    >
    > char const tmp = *p_last;
    >
    > *p_last = 0;
    >
    > puts(p);
    >
    > *p_last = tmp;
    > }



    I should have written the function parameter as:

    char * const p



    --

    Frederick Gotham
     
    Frederick Gotham, Jul 15, 2006
    #9
  10. Snis Pilbor

    Tim Prince Guest

    Jack Klein wrote:

    >
    > int my_strlen1(const char *x)
    > {
    > int count = 0;
    > while (*x)
    > {
    > ++count;
    > ++x;
    > }
    > return count;
    > }
    >
    > int my_strlen2(char *x)
    > {
    > int count = 0;
    > while (*x)
    > {
    > ++count;
    > ++x;
    > }
    > return count;
    > }
    >
    > int main(void)
    > {
    > const char *str = "Hello, World!";
    > int l1 = my_strlen1(str);
    > int l2 = my_strlen2(str);
    > puts(str);
    > return 0;
    > }

    Current compilers exhibit a wide variety of behaviors in this situation.
    Even within the same compiler family, one compiler may not have any
    diagnostic available, and will link and run without problem, and another
    may fail, particularly if the C code is compiled under C++.
    I filed a problem report against a compiler for linux x86-64 which has
    no available diagnostic or failure mode, while its Windows x64 sibling
    runs into trouble later in the compilation.
    With gcc 4.2, I saw a change in behavior between -m64 and -m32, where
    the original problem is diagnosed directly only in -m64 mode, and the
    consequences depend on context (even though the string is never
    re-written). This contributed to my difficulty in convincing a bug
    report team of the desirability of the diagnostic.
    The f2c translator, even in "ansi" mode, generates legacy style code
    which passes string constants without using "const" in the prototypes,
    and that has only recently begun to fail.
     
    Tim Prince, Jul 15, 2006
    #10
  11. Snis Pilbor

    REH Guest

    "Snis Pilbor" <> wrote in message
    news:...
    >
    > Not to be argumentative, but consider the following two versions of the
    > same function:
    >
    > void print_first_5( char *x )
    > {
    > char buf[6];
    > int i;
    >
    > for ( i = 0; i < 5; i++ )
    > buf = x;
    >
    > buf[5] = '\0';
    > printf( buf );
    > }
    >
    > void print_first_5( char *x )
    > {
    > char tmp;
    >
    > tmp = x[5];
    > x[5] = '\0';
    > printf( x );
    > x[5] = tmp;
    > }
    >
    > As far as I can tell, the 2nd is both faster and takes less memory.
    > The two do the exact same thing, assuming that printf itself acts
    > nondestructively. If I used const to tell the compiler that
    > print_first_5 acts nondestructively on x in the 2nd version, the
    > compiler would think I was mistaken even though I'm correct. The point
    > is, the change can hardly be said to "change the very nature of this
    > function", and if this were deeply nested in a family of functions
    > using const arguments, a massive headache would arise.
    >


    First, I would output the characters directly and not copy them, nor modify
    the original array. Secondly, the convenience and safety of not
    unnecessarily modifying the input parameter outweighs any performance you
    think you are losing. Unless it is a real issue (and since you are writing
    to output, I seriously doubt it), don't worry so much about which is
    "faster." By not modifying the string, the function can be used with both
    modifiable and non-modifiable strings, and in this case, that probably
    better than any perceived loss in speed.


    REH
     
    REH, Jul 15, 2006
    #11
  12. Snis Pilbor

    Skarmander Guest

    Frederick Gotham wrote:
    > Jack Klein posted:
    >
    >
    >>> 2. Used to alert the compiler that some kind of extra optimization is
    >>> possible, which wouldn't be possible if the data in question were
    >>> manipulated? And if so, exactly what sort of optimization would this
    >>> be?

    >> The C standard does not define optimizations. There might well be
    >> optimizations possible with data pointed to by a pointer to const, but
    >> that is an implementation detail and off-topic here.

    >
    >
    > Yes, that must be the exact reason why we have a "register" keyword.
    >
    > I suppose "inline" has nothing to do with optimisation either.
    >
    >

    Your sarcasm is misplaced; optimization is indeed not the primary intent of
    "const". By that reasoning you might call static typing an optimization. It
    may allow optimization, but that's not its primary benefit.

    Moreover, the standard really *doesn't* define optimizations, it merely
    standardizes certain hints to the compiler (which is free to ignore them).
    I've seen plenty of compilers that all but ignore the "register" keyword,
    for example, because they can do a far better job of register allocation
    than any human programmer could (especially across different platforms). The
    "register" keyword is a holdover from less sophisticated times.

    Compilers that support "inline" tend to respect it (and some even have a
    corresponding "noinline" keyword), since determining what functions to
    inline is not something that compilers are perfect at yet (and may never
    become, since in many cases profiling is required).

    The mere fact that the standard gives these optimization hints uniform names
    and guarantees that programs can use them should not be taken as an
    indication that the standard is in the business of telling implementations
    how to optimize. In fact, that would be anathema to the C philosophy of
    leaving things unsaid that don't need to be said.

    S.
     
    Skarmander, Jul 15, 2006
    #12
  13. Snis Pilbor

    Eric Sosman Guest

    Snis Pilbor wrote:
    > Frederick Gotham wrote:
    >
    >>Snis Pilbor posted:
    >>(snip)
    >>
    >>
    >>>Quite the opposite, if one uses const
    >>>liberally and then later goes back and changes the functions, headaches
    >>>will inevitably occur as one tries to compile and the compiler gripes
    >>>because now suddenly you ARE writing to x, so you have to go back and
    >>>remove the const keyword, and this might mean painstakingly removing it
    >>>from dozens of lines if the function in question is deeply nested
    >>>amidst a family of functions that call eachother and all have 'const'
    >>>keywords.

    >>
    >>
    >>Revising whether a function alters its argument changes the very nature of
    >>the function!
    >> (snip)

    >
    >
    > Not to be argumentative, but consider the following two versions of the
    > same function:
    >
    > void print_first_5( char *x )
    > {
    > char buf[6];
    > int i;
    >
    > for ( i = 0; i < 5; i++ )
    > buf = x;
    >
    > buf[5] = '\0';
    > printf( buf );
    > }
    >
    > void print_first_5( char *x )
    > {
    > char tmp;
    >
    > tmp = x[5];
    > x[5] = '\0';
    > printf( x );
    > x[5] = tmp;
    > }
    >
    > As far as I can tell, the 2nd is both faster and takes less memory.
    > The two do the exact same thing, assuming that printf itself acts
    > nondestructively. If I used const to tell the compiler that
    > print_first_5 acts nondestructively on x in the 2nd version, the
    > compiler would think I was mistaken even though I'm correct. The point
    > is, the change can hardly be said to "change the very nature of this
    > function", and if this were deeply nested in a family of functions
    > using const arguments, a massive headache would arise.


    Neither version is any damned good; no decent programmer
    would write either one of them. A few flaws:

    - Try the first version with the argument "X". What happens
    when it tries to read elements [2] through [4] of this
    two-element array?

    - Try the second version with the argument "X". What happens
    when it stores a zero in element [5] of this two-element
    array? (Even if it doesn't segfault immediately, how sure
    are you that whatever got clobbered isn't used by printf()?)

    - Try either version with the argument "%solved". Somebody
    doesn't know how to use printf() safely ...

    - Try the second version with "Hello, world!" on an
    implementation that puts string literals in read-only
    memory. (Extra credit: defend your "I'm correct" claim.)

    Arguments can be made for and against aspects of a programming
    language, but arguments based on broken code carry little weight.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Jul 15, 2006
    #13
  14. Snis Pilbor

    Malcolm Guest

    "Snis Pilbor" <> wrote in message
    >
    > Is const, in this context (ie passing const arguments to functions)....
    >
    > 1. A Java-like "babysitter" keyword based on the premise that all
    > programmers are idiots and must have their hands held at all times?
    > 2. Used to alert the compiler that some kind of extra optimization is
    > possible, which wouldn't be possible if the data in question were
    > manipulated? And if so, exactly what sort of optimization would this
    > be?
    > 3. About as useful as a comment, with no other purpose but as a little
    > yellow sticky note saying "this function should act nondestructively on
    > this particular thing"?
    >
    > I always assumed it was some combination of 1 and 3 and so I tend to
    > never, ever use the thing...
    >

    const is an addition to C.
    It adds no functionality, and it doesn't really help the compiler to
    optimise though someone might be able to come up with examples using pointer
    aliasing or something similar.

    It is a combination of 1 and 3. It is perfectly possible to write correct
    code without const, unless you are an idiot programmer. So for idiot
    programmers it might useful to be told that they are trying to write to a
    const-qualified object.
    Consider this function

    void copy_string(char *str1, char *str2);

    by looking at the prototype, you cannot tell which parameter is which.

    void copy_string(const char *str1, char *str2);

    tells you that the first parameter must be the source, so it is the other
    way round to strcpy(). That's obviously handy.

    The reason a lot of people don't like const is "const-poisoning". Once an
    object is declared const, everything derived for it must be const, even it
    is isn't really a constant.

    The second problem is this

    struct employee
    {
    char *name;
    float salary;
    };

    void payroll(const employee *emp)
    {

    /* evil hacker */
    strcpy(emp[0]->name, "Fred the Hacker");
    pay(&emp[0]);
    }
     
    Malcolm, Jul 16, 2006
    #14
  15. Snis Pilbor

    Chris Torek Guest

    [The OP, writing about "const" qualifiers, asked whether const-qualified
    arguments were...]

    >>>> 2. Used to alert the compiler that some kind of extra optimization is
    >>>> possible, which wouldn't be possible if the data in question were
    >>>> manipulated? And if so, exactly what sort of optimization would this
    >>>> be?


    >> Jack Klein posted:
    >>> The C standard does not define optimizations. There might well be
    >>> optimizations possible with data pointed to by a pointer to const, but
    >>> that is an implementation detail and off-topic here.


    >Frederick Gotham wrote:
    >> Yes, that must be the exact reason why we have a "register" keyword.
    >>
    >> I suppose "inline" has nothing to do with optimisation either.


    In article <44b9435c$0$31653$4all.nl>
    Skarmander <> wrote:
    >Your sarcasm is misplaced; optimization is indeed not the primary intent of
    >"const". By that reasoning you might call static typing an optimization. It
    >may allow optimization, but that's not its primary benefit.


    Indeed, it is quite a bit worse than this. C's "const" qualifiers
    rarely allow any optimization at all!

    Consider the following function:

    int zog(const char *p) {
    int result;

    for (result = 0; *p; result++)
    if (otherfunc())
    break;
    return result;
    }

    The loop inside this function repeatedly inspects *p. Well, we
    claimed that *p was "const", so it will not change, right? Thus
    the compiler can rewrite this as:

    result = 0;
    if (*p) {
    while (otherfunc() == 0)
    result++;
    }
    return result;

    right?

    Alas, wrong:

    #include <stdio.h>

    char buf[100];

    int otherfunc(void) {
    buf[42]--;
    return 1;
    }

    int main(void) {
    buf[42] = 12;

    printf("%d\n", zog(&buf[42]));
    return 0;
    }

    Each call to otherfunc() decrements buf[42], and *p inside zog is
    just another name for buf[42]. The loop must in fact re-test *p
    each time, and the code above must print 12.

    In other words, even though zog() does not change *p, something
    *else* might change it, despite the "const". Const does not mean
    constant; it means "read-only". Read-only, but changing each time,
    in this case.

    In most (but not all) cases, "const" helps only when it is plainly
    obvious that the variable has not changed, in which case, any decent
    C compiler can substitute in the unchanged variable:

    void zog2(void) {
    const int i = 2;

    while (i == 2)
    other2();
    }

    Since nothing takes i's address here, it is impossible for i to
    change. The const only helps make it clear that this is still
    an infinite loop even if we pass &i to other2():

    while (i == 2)
    other2(&i);

    Here, if i is *not* const, other2() can change it, but if i *is*
    const, other2() cannot change it (without producing undefined
    behavior, anyway).

    The ugliest (in my opinion anyway) situation of all occurs when
    C functions are forced to cast away "const"-ness from pointers in
    their return values:

    char *strchr(const char *s, int lookfor0) {
    char lookfor = lookfor0;

    for (; *s != c; s++)
    if (*s == 0)
    return NULL;
    return (char *)s;
    }

    Fortunately, this mostly occurs in "legacy" routines like strchr(),
    which the implementor (i.e., me :) ) has to write for the user
    (i.e., you) -- most programmers are not forced to do this.
    --
    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, Jul 16, 2006
    #15
  16. Snis Pilbor

    Bill Pursell Guest

    Chris Torek wrote, in reference to const being used
    to aid optimization:

    > C's "const" qualifiers
    > rarely allow any optimization at all!
    >
    > Consider the following function:
    >
    > int zog(const char *p) {
    > int result;
    >
    > for (result = 0; *p; result++)
    > if (otherfunc())
    > break;
    > return result;
    > }


    [Where otherfunc() manipulates a global that p
    references.]

    Isn't this the point of the restrict keyword? eg, your
    function doesn't allow
    int zog(const char *restrict p),
    but if otherfunc didn't tweak *p, you could prototype
    it that way and reap the benefits of the optimization.
     
    Bill Pursell, Jul 16, 2006
    #16
  17. Malcolm wrote:
    > The second problem is this
    >
    > struct employee
    > {
    > char *name;
    > float salary;
    > };
    >
    > void payroll(const employee *emp)


    ? void payroll(const employee **emp)

    > {
    >
    > /* evil hacker */
    > strcpy(emp[0]->name, "Fred the Hacker");


    ? strcpy(emp->name, "Fred the Hacker");

    > pay(&emp[0]);
    > }


    void payroll(const employee *emp);

    In this case, the const keyword qualifies the object it points to as
    constant. The object `name' is that one pointed by emp, so this is an
    error:
    /*(*emp).name = "C";*/

    The object `*name' is pointed by name, not emp. That const does not
    prevent following from being done:
    *(*emp).name = 'c';

    ? void payroll(const employee **emp)

    So does the const keyword applying to multiple-level pointer.
    /*(**emp).name = "C";*/
    *(**emp).name = 'c';

    lovecreatesbeauty
     
    lovecreatesbeauty, Jul 16, 2006
    #17
  18. Snis Pilbor

    Chris Torek Guest

    >Chris Torek wrote, in reference to const being used
    >to aid optimization:
    >> Consider the following function:
    >>
    >> int zog(const char *p) {
    >> int result;
    >>
    >> for (result = 0; *p; result++)
    >> if (otherfunc())
    >> break;
    >> return result;
    >> }


    In article <>,
    Bill Pursell <> wrote:
    >[Where otherfunc() manipulates a global that p
    >references.]
    >
    >Isn't this the point of the restrict keyword?


    Yes. It turns out that "char *restrict p", or perhpas
    "const char *restrict p", means what most people thought
    "const char *p" was going to mean.

    >eg, your function doesn't allow
    >int zog(const char *restrict p),
    >but if otherfunc didn't tweak *p, you could prototype
    >it that way and reap the benefits of the optimization.


    Indeed. (By "prototype" I assume you mean "both declare and
    define".) The "optimization" -- hoisting the *p test out of the
    loop -- needs to takes place during compilation of the function
    zog() itself, hence the the "restrict" has its main effect inside
    the definition, rather than at some external prototype. Of course,
    it is a good idea to make sure that every prototype declaration
    for every function always matches the actual definition of the
    function.
    --
    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, Jul 16, 2006
    #18
  19. Chris Torek wrote:
    > >Chris Torek wrote, in reference to const being used
    > >to aid optimization:
    > >> Consider the following function:
    > >>
    > >> int zog(const char *p) {
    > >> int result;
    > >>
    > >> for (result = 0; *p; result++)
    > >> if (otherfunc())
    > >> break;
    > >> return result;
    > >> }

    >
    > In article <>,
    > Bill Pursell <> wrote:
    > >[Where otherfunc() manipulates a global that p
    > >references.]
    > >
    > >Isn't this the point of the restrict keyword?

    >
    > Yes. It turns out that "char *restrict p", or perhpas
    > "const char *restrict p", means what most people thought
    > "const char *p" was going to mean.


    Although the below code is definitely poor style, is any rule actually
    violated?

    void f(const int *restrict p) {
    *(int *) p = 0;
    }
    int main(void) {
    int i = 1;
    f(&i);
    return i;
    }
     
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, Jul 16, 2006
    #19
  20. Snis Pilbor

    Malcolm Guest

    "lovecreatesbeauty" <> wrote in message
    >
    > Malcolm wrote:
    >> The second problem is this
    >>
    >> struct employee
    >> {
    >> char *name;
    >> float salary;
    >> };
    >>
    >> void payroll(const employee *emp)

    >
    > ? void payroll(const employee **emp)
    >
    >> {
    >>
    >> /* evil hacker */
    >> strcpy(emp[0]->name, "Fred the Hacker");

    >
    > ? strcpy(emp->name, "Fred the Hacker");
    >

    Should be a dot.
    Silly mistake, but easy to make. Or get rid of the [0].
    The point is the hacker is allowed to insert his own name into the employee
    list and, presumably, get the salary paid into his own account, despite the
    fact that the distrustful high level programmer thinks the structure is
    const.
    >
    >
    >> pay(&emp[0]);
    >> }

    >
    > void payroll(const employee *emp);
    >
    > In this case, the const keyword qualifies the object it points to as
    > constant. The object `name' is that one pointed by emp, so this is an
    > error:
    > /*(*emp).name = "C";*/
    >
    > The object `*name' is pointed by name, not emp. That const does not
    > prevent following from being done:
    > *(*emp).name = 'c';
    >
    > ? void payroll(const employee **emp)
    >
    > So does the const keyword applying to multiple-level pointer.
    > /*(**emp).name = "C";*/
    > *(**emp).name = 'c';
    >
    > lovecreatesbeauty
    >


    --
    Buy my book 12 Common Atheist Arguments (refuted)
    $1.25 download or $7.20 paper, available www.lulu.com/bgy1mm
     
    Malcolm, Jul 16, 2006
    #20
    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. Amol Chavan
    Replies:
    1
    Views:
    307
    Karl Heinz Buchegger
    Aug 13, 2003
  2. rbt

    deal or no deal

    rbt, Dec 22, 2005, in forum: Python
    Replies:
    7
    Views:
    553
    Duncan Smith
    Dec 28, 2005
  3. =?gb2312?B?wNbA1rTzzOzKpg==?=
    Replies:
    26
    Views:
    6,543
    Ian Collins
    Jan 30, 2007
  4. Replies:
    11
    Views:
    1,109
  5. Javier
    Replies:
    2
    Views:
    569
    James Kanze
    Sep 4, 2007
Loading...

Share This Page