const qualifier used on a function argument

This is a discussion on const qualifier used on a function argument within the C Programming forums, part of the General Programming Boards category; The "Const Correctness" article ( http://cprogramming.com/tutorial/const_correctness.html ) says "the data referred to (i.e. qualified by const) won't be changed", and ...

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    98

    const qualifier used on a function argument

    The "Const Correctness" article (http://cprogramming.com/tutorial/const_correctness.html) says "the data referred to (i.e. qualified by const) won't be changed", and "by declaring the argument [of a function]const, users of the function can be sure that their object will not be changed".
    Wiki's entry on Const correctness (http://en.wikipedia.org/wiki/Const_correctness) says "const-ness is a compile-time construct that indicates what a programmer may do, not necessarily what he or she can do."
    Tru64 UNIX Compaq C Language Reference Manual (http://h30097.www3.hp.com/dtk/Compaq...m/DOCU0008.HTM) says "Objects qualified by the const keyword cannot be modified."

    What do these "won't be changed", "may not be changed", "cannot be changed" mean?

    I have this code:
    Code:
    static char *s;
    
    void func(const char* str)
    {
      s = str;
    }
    
    int main()
    {
      func(s);
      return 0;
    }
    % gcc testconst.c -o testconst
    testconst.c: In function `func':
    testconst.c:5: warning: assignment discards qualifiers from pointer target type

    I do not change str inside func. Why does gcc give me a warning? Does it complain because after I assign str to s, *str can be changed outside func? Does this unmodifiability apply to the entire program, not just within the visibility scope of the variable in question (i.e. *str)? And does this unmodifiability refer to actual unmodifiability or potential unmodifiability? That is, if I assign str to some other pointer, I then have the ability to change what is pointed to by str by using the other pointer. But does it matter whether I actually use that ability or not? Can I still use that const qualifier if I never exercise that ability to change the string through another pointer?

    Here is another example:
    Code:
    void
    initHelper(char **helper, const char *array, int sizeOfEle,
               int start2, int len1, int len2)
    {  
      int i;
    
      for( i=0; i<len1; i++ ) {
        helper[i] = array + (i * len2 - start2) * sizeOfEle;
      }
    }
    gcc gives me the same warning msg as above. I never actually change *array inside the function!

    By the way, how should I qualify a string, like in char *argv[] (or char **argv), using const? That is, the strings pointed to by argv[0], argv[1], etc, "will not be changed" (whatever that means). Is it "const char *argv[]"?

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    the bottom line for const qualification is that the compiler *will not* allow you alter a const object though it *will* allow you to convert it to a non-const object - whatever you do with it after that is undefined - if the data is stored in read-only memory an access violation might occur, if not, probably nothing. the important thing is that conversion should be reserved for situations where is can't be avoided and there is a very good reason for doing so in the first place.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,290
    main() can't be specified with const qualifiers on it's arguments (not if your care about portability). And a lot of programs/libraries that fiddle with their command line arguments do actually change the command line arguments received. For example, the CORBA specification requires passing of command line arguments when initialising an ORB, and the initialisation routine removes command line options that it interprets.

    Things can get interesting when an argument is passed via both const and non-const means to a function. For example;
    Code:
    void Function(int *x, const int *y)
    {
         *x = 5;
        /*   what value do we expect if we access *y ? */
    }
    
    int main()
    {
          int x = 42;
          Function(&x, &x);
    }

  4. #4
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by Sebastiani
    the bottom line for const qualification is that the compiler *will not* allow you alter a const object ...
    Forgive me but I think this statement is as vague as the ones I cited in my original post. The thing I was asking is exactly what it really means by saying the compiler will not allow one to alter the const object. What is the scope of this prohibition? Is this prohibition refer to the actual change or potential change?

  5. #5
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by grumpy
    main() can't be specified with const qualifiers on it's arguments (not if your care about portability).
    I assume this is in response to my *argv[] question. Let's say this argv is not referring to the command line arguments. Let's call it *string[]. How about that?

  6. #6
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,535
    > I do not change str inside func. Why does gcc give me a warning?
    While str[0] = 'a' would get you another warning about trying to modify a const, s[0] = 'a' would be just fine (you've now subverted the const-ness).

    > Does it complain because after I assign str to s, *str can be changed outside func?
    No, it's because s lacks a const qualifier.
    as in
    const char *s;
    But then I think making s a global is just clouding the issue.

    > And does this unmodifiability refer to actual unmodifiability or potential unmodifiability?
    It doesn't matter
    Code:
    char msg[] = "a writable string";
    func( msg );
    func( "a string constant" );
    All that you're saying is that func() won't cause the string to be modified, that is to say the variable msg will not change as a result of calling func().

    > But does it matter whether I actually use that ability or not?
    Well that depends doesn't it - do you really want it to be const or not.
    There's no point declaring things const if you're just going to remove the const later on just because you can. Presumably, if you go to the trouble of declaring it const, then you'd be expecting a warning if you were about to lose const again.

    > I never actually change *array inside the function!
    No, but the caller function through the returned pointers of helper could do.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Is this prohibition refer to the actual change or potential change?

    both. you can't *directly* modify a const identifier nor can you *implicitly* convert it to a non-const identifier. I say 'identifier' because 'object' implies the *thing* itself - const qualification really has less to do with what actually happens to an object than how the object is accessed through the identifiers associated with it. in other words, it is not a protection mechanism so much one of type checking.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by Salem
    > And does this unmodifiability refer to actual unmodifiability or potential unmodifiability?
    It doesn't matter

    > I never actually change *array inside the function!
    No, but the caller function through the returned pointers of helper could do.
    I think your remarks illustrate exactly why I am confused. In the first part, you say "it does not matter" but in the last part, what you really say, if I understand it correctly, is it does matter - the unmodifiability refers to potential unmodifiability. (The word "could" is used - the caller function could possibly change the string value but it may not actually do it.) The fact seems to be that even if I actually do not change the value of the string parameter - neither inside nor outside the function, qualifying the parameter with const would give a gcc warning if I assign the pointer to another pointer that is not const-qualified, even though I do not actually change the string value through the const-unqualified pointer. The mere potential, or possibility, that I may change the string value via the second pointer is sufficient to cause a gcc warning.
    Last edited by hzmonte; 04-17-2006 at 12:45 AM.

  9. #9
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by Sebastiani
    >> Is this prohibition refer to the actual change or potential change?

    both. you can't *directly* modify a const identifier nor can you *implicitly* convert it to a non-const identifier. I say 'identifier' because 'object' implies the *thing* itself - const qualification really has less to do with what actually happens to an object than how the object is accessed through the identifiers associated with it. in other words, it is not a protection mechanism so much one of type checking.
    Would it be clearer if I say "const qualification really has less to do with what _actually_ happens to an object than how the object _may possibly be_ accessed through the identifiers associated with it."?
    And since the compiler, not the run-time, is responsible for checking the const-ness, the compiler is more conservative and treats any such possiblility, though not realized during runtime, as a violation of the const-ness and give a warning.
    So correct me if I am wrong, all those "won't be changed", "may not be changed", "cannot be changed" things do not refer to any actual change, but refer to any possible change that may happen at run-time which the compiler is not able to tell for sure.
    Last edited by hzmonte; 04-17-2006 at 12:49 AM.

  10. #10
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,535
    Ah, I see what you're getting at (I think)
    Code:
    void func ( char **helper, const char *array ) {
      helper[0] = array;
    }
    int main ( ) {
      char msg[] = "hello world";
      char *helper[2];
    
      func( &helper, msg );
      helper[0][0] = 'H';  // modifies msg[0]
    
      func( &helper, "string constant" );
      helper[0][0] = 'S';  // segfault?
      return 0;
    }
    In the first instance, the const should just be diagnosing local attempts to modify the variable. The input array isn't const to begin with, so it should be reasonable to expect to be able to modify it afterwards via the return result. Unfortunately, the const is a 'sticky' attribute and it propagates through assignments.

    In the second instance, it's saying that the input is really const and that should be propagated to other pointers as well. Indeed, it would be nice to diagnose helper[0][0] = 'S' at compile time rather than at run-time (or worse, some random crash much later on).

    Ideally of couse, we would have had
    const char *helper[2];
    func( &helper, "string constant" );
    But then the compiler would have complained about the first parameter losing const!

    It's like we need
    void func ( char **helper, char *array );
    void func ( const char **helper, const char *array );
    but C doesn't have anything like that kind of overloading ability to be able to resolve all the possible meanings.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  11. #11
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    1. I gave up on the initHelper() example after I read comp.lang.c FAQ 11.10 (http://c-faq.com/questions.html). There is simply too much complication for me to handle and it is not a good example to highlight the issue which i want to investigate.
    2. I construct a simpler example:
    Code:
    char * func ( const char *array ) {
      char *array1 = array;
      //array[0] = 'H';
      return array1;
    }
    
    int main ( ) {
      char *msg;
      char *msg1;
    
      msg = malloc(20);
      sprintf(msg, "hello world");
      msg1 = func(msg);
    }
    As the code stands now, gcc issues a warning: " warning: initialization discards qualifiers from pointer target type"
    Well, a warning is just a warning that something _may_ go wrong. So, I guess any one can issue a warning about anything. It does not mean that what I do violate the C Standard. (And I think I do not violate the C Standard. Though I do not have the C Standard on hand, C FAQ 1.20b implies that it is not inconsistent with C Standard if I const-ify a function parameter and never actually change it inside the function - it says "many functions declare parameters which are pointers to const data, and doing so documents (and tends to enforce) the function's promise that it [i.e. the function]won't modify the pointed-to data in the caller." So the (only) promise is that the pointed-to data is not changed inside the function. It does not care whether the pointed-to data is actually changed outside the function. gcc can give all the warnings it wants (and this warning is probably an over-reaction) but apparently the const does not propogate outside the function - at least that's what the C FAQ suggests, as I understand.)
    If I remove the const from func's parameter, then there is no warning and the program executes fine, as anticipated.
    If I uncomment the "array[0] = 'H';", then gcc issues the above warning plus an error: "error: assignment of read-only location". This error is understandable and expected (had it not for the wording of the warning).
    Now what I do not understand is the wording of the gcc warning: initialization discards qualifiers from pointer target type. It seems to suggest that gcc discards/ignores the const qualifier. If that's the case, then there would and should not be an error when I try to change h to H!
    Any insight?

    Can anyone check on the official C Standard to see what exactly it says about 'const'?
    Last edited by hzmonte; 04-17-2006 at 09:59 PM.

  12. #12
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,006
    Quote Originally Posted by hzmonte
    Now what I do not understand is the wording of the gcc warning: initialization discards qualifiers from pointer target type. It seems to suggest that gcc discards/ignores the const qualifier. If that's the case, then there would and should not be an error when I try to change h to H!
    Any insight?
    The compiler is trying to do what you are telling it to do. In the initialization, you are taking a pointer to const and assigning its value to a non-const pointer. This may result in undefined behavior, and the compiler informs you of possible issues.

    It's up to you to look at the suspect code and determine whether or not you actually do modify the pointed-to contents, or rather to instead change the type to better match the intention. I see the diagnostic as saying, "Hey, shouldn't array1 be a const char *?"

    Quote Originally Posted by hzmonte
    Can anyone check on the official C Standard to see what exactly it says about 'const'?
    An archive of C89, but it's rather dry. C99 isn't much more fun. [edit]But I believe the key wording is as such:
    If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
    Last edited by Dave_Sinkula; 04-17-2006 at 10:41 PM.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  13. #13
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by Dave_Sinkula
    The compiler is trying to do what you are telling it to do. In the initialization, you are taking a pointer to const and assigning its value to a non-const pointer. This may result in undefined behavior, and the compiler informs you of possible issues.
    I am inclined to disagreeing that discarding the const qualifier is what I am telling the compiler to do, if that's what you mean. Yes, I am taking a pointer to const and assigning its value to a non-const pointer, but that does not mean the const qualifier has to be discarded. I located the May 5, 2005 Committee Draft of the C Standard (http://www.open-std.org/jtc1/sc22/wg...ocs/n1124.pdf). Paragraph 5 of Section 6.7.3 (page 109) has the exact sentence as you cited in the C89 Standard. It implies that if there is no (actual) attempt made to modify the pointed-to data, then the use of the const qualifier is okay. And if the use of the const qualifier is allowed by the C Standard, then there is no reason to discard the qualifier. So, no, I did not tell gcc to discard the const qualifier. And what results in undefined result is an (actual) attempt to modify the pointed-to data, not taking a pointer to const and assigning its value to a non-const pointer. If there is no attempt to modify the data, then there is no undefined result, even though I take a pointer to const and assigning its value to a non-const pointer. That is, as long as I stop short of attempting to modify the data, I am in compliance with the C Standard as far as const is concerned.
    And gcc does more than informing me of the possible issues, it discards the const qualifier! And if it discards the const qualifier, then apparently a subsequent modification of the pointed-to data would be allowed! That's the inconsistency - on one hand, it discards the const, on the other hand, it issues an error disallowing me to modify the data.

    Quote Originally Posted by Dave_Sinkula
    I see the diagnostic as saying, "Hey, shouldn't array1 be a const char *?"
    Well, if the warning says something like what you see as saying, then I am perfectly satisfied. But again, it issues a warning AND discards the const qualifier. I guess discarding the qualifier is at the discretion of the compiler. C Standard does not prohibit a compiler from doing that. But if the compiler discards the const, can it turn around and prohibit me from modifying the data?

    [Edit] It is like you are late in paying your mortgage. The bank takes your late payment - but still declares a default and forecloses your house. Can the bank have the cake and eat it too? Isn't that a bit too harsh?
    I am also wondering whether gcc is overreacting by issuing a warning (not to mention its discarding the const qualifier). As explained above, taking a pointer to const and assigning its value to a non-const pointer is not a violation of the C Standard. Further, an actual attempt to modify the data can be detected by gcc, which issues an error. So, a warning (not to mention the discarding of the const) appears to be unnecessary.[/Edit]
    Last edited by hzmonte; 04-18-2006 at 12:16 AM.

  14. #14
    Registered User
    Join Date
    Jul 2005
    Posts
    98
    Quote Originally Posted by hzmonte
    So correct me if I am wrong, all those "won't be changed", "may not be changed", "cannot be changed" things do not refer to any actual change, but refer to any possible change that may happen at run-time which the compiler is not able to tell for sure.
    Just for the record, given what I have found (i.e. what the official C Standard says), the modifiability refers to actual change, not possible change. That is, even though it is possible to change the data through the non-const-qualified pointer, there is no nonconformance with the C Standard as long as there is no actual attempt to change the data.

  15. #15
    Registered User
    Join Date
    Jun 2004
    Posts
    201
    there are lots of things not prohibited by the C standard, but do cause undefined behaviour.

    First just consider it bad style to assign a const variable to a non const variable.
    Second, on some systems variables declared as const might be put into a read-only section of the executable or are put on an EPROM. So if you get a non const pointer to that data and later try to change it the system will probably crash.

    third, the compiler might be able to see in this instance that the non-const variable never changes value, but things are often way harder in C to detect. you can have pointers everywhere, pointers to pointers, const data coming from a dynamic library etc. Maybe a system could be implemented by gcc to detect all possible const to non-const violations, but that would be really hard if not impossible.
    So gcc decides to give the warning at the time it's easiest to detect and where the bad style programming actually occurs.

    so if you think you really know what you are doing and that never ever in the future the non const will change what it points to just cast! s = (char *)s1; imo just a source for hard to find bugs but be my guest
    Last edited by Laserve; 04-18-2006 at 12:44 AM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. seg fault at vectornew
    By tytelizgal in forum C Programming
    Replies: 2
    Last Post: 10-25-2008, 01:22 PM
  2. Code review
    By Elysia in forum C++ Programming
    Replies: 71
    Last Post: 05-13-2008, 09:42 PM
  3. Including lib in a lib
    By bibiteinfo in forum C++ Programming
    Replies: 0
    Last Post: 02-07-2006, 01:28 PM
  4. Problem with Visual C++ Object-Oriented Programming Book.
    By GameGenie in forum C++ Programming
    Replies: 9
    Last Post: 08-29-2005, 11:21 PM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21