# C99 const keyword - indirection

## Recommended Posts

I did quick googling on this but the explanations found are too simple (eg. "a const object is unmodifiable"). Ok, say I have a struct and two functions like this:
typedef struct
{
otherstruct_t* ptr;
} somestruct_t;

void do_something(const somestruct_t* s)
{
s->ptr->... = ...;
}

somestruct_t* return_something(const somestruct_t* array, int index)
{
return &array[index];
}


What gives in these cases? I thought that const implies I can't write directly in the type qualified (not counting indirection) in the scope of the function, but I get GCC warning me about constness getting discarded by functions similar to the two above. I've probably misunderstood the keyword. I'm not completely inexperienced with C but I didn't bother with this qualifier before, this time however I'd like to help the compiler's optimizer unless it gives me too much of a headache.

##### Share on other sites
Above code is not compilable, and I can't really imagine what you mean exactly; please post real code, not pseudo code.

Wikipedia has a nice page about const correctness, as well as the C++ FAQ Lite.

##### Share on other sites
It's pseudo in that I have not written out a definition for otherstruct_t, which is another structure. Nor have I written out the assignment. But it shouldn't matter for the understanding of the problem.

Don't know if reading about C++ constness will help, considering there are differences in how C deals with constants compared to C++.

Will check out wiki, thanks.

##### Share on other sites
Just checked some code that I think you really mean (C++ though):

struct somestruct_t{   somestruct_t* ptr;};somestruct_t* return_something(const somestruct_t* array, int index){   return array + index;}

This won't compile, because gcc spits an error for trying to implicitly discard the const qualifier.

##### Share on other sites
Quote:
 Original post by Beyond_RepairIt's pseudo in that I have not written out a definition for otherstruct_t, which is another structure. Nor have I written out the assignment. But it shouldn't matter for the understanding of the problem.

It matters, because

somestruct_t* return_something(const somestruct_t* array, int index){   return array[index];}

is invalid code. Function return_something accepts a const somestruct_t* as a parameter, and by signature returns a somestruct_t*; but actually your return statement tries to return a somestruct_t, i.e. invalid code.

##### Share on other sites
It does compile, but I'm allowing warnings (not like it matters as I always fix them and never lead them to be, like in this case). :P

Edit: Uggh, I forgot the address of operator in my example. Sorry-.

##### Share on other sites

* C++ FAQ Lite, [18]
* Wikipedia: Const Correctness

##### Share on other sites
Quote:
 Original post by Beyond_RepairIt does compile, but I'm allowing warnings (not like it matters as I always fix them and never lead them to be, like in this case). :P

Okay, now I am really in C. Let me dig ...

##### Share on other sites
Aha, Wikipedia probably answers my question:

Quote:
 Another loophole applies both to C and C++. Specifically, the languages dictate that member pointers and references are "shallow" with respect to the const-ness of their owners — that is, a containing object that is const has all const members except that member pointees (and referees) are still mutable.

Weird GCC is giving me a warning then, but I guess it's because it's not "recommended".

##### Share on other sites
Quote:
Original post by Beyond_Repair
Aha, Wikipedia probably answers my question:

Quote:
 Another loophole applies both to C and C++. Specifically, the languages dictate that member pointers and references are "shallow" with respect to the const-ness of their owners — that is, a containing object that is const has all const members except that member pointees (and referees) are still mutable.

Weird GCC is giving me a warning then, but I guess it's because it's not "recommended".

What is the warning and what gcc version?
The following produces no warnings using:
gcc -ansi -pedantic -Wall -Wextra const_aware.c #include <malloc.h>typedef struct{ int i;} otherstruct_t;typedef struct{ otherstruct_t* ptr;} somestruct_t;void do_something(const somestruct_t* s){ s->ptr->i = 2;}const somestruct_t* return_something(const somestruct_t* array, int index){ return array + index;}int main(){ somestruct_t* s = malloc(sizeof(somestruct_t)); s->ptr = malloc(sizeof(otherstruct_t)); s->ptr->i = 1; do_something(s); free(s->ptr); free(s); return 0;} #### Share this post ##### Link to post ##### Share on other sites Quote:  Original post by Beyond_RepairEdit: Uggh, I forgot the address of operator in my example. Sorry-. Better do actual copy+paste next time ;) Hmm, as far as I can tell, the C99 standard (http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf) allows such conversion: Quote:  6.3.2.3 Pointers7. A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned57) for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. [...] Though I am unsure if it allows such conversion to be implicit as in your example. digs further edit: Hmm, unsure whether that was the right item. Another item says Quote:  6.3.2.3 Pointers2. For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal. So you would be allowed to convert T* to const T*, but that item does not, imho, allow const T* to T*. The wording is a bit unsharp for the german in me, but I think in those two quotes, "object" means "object type", "incomplete" means "incomplete type", even if only "object"/"incomplete" is written down. Now I am confused whether item 7 or item 2 is relevant. Quote: Original post by Beyond_Repair Aha, Wikipedia probably answers my question: Quote:  Another loophole applies both to C and C++. Specifically, the languages dictate that member pointers and references are "shallow" with respect to the const-ness of their owners — that is, a containing object that is const has all const members except that member pointees (and referees) are still mutable. Unfortunately not, array elements are not member pointers or references. #### Share this post ##### Link to post ##### Share on other sites Quote:  6.5.4 Cast Operators3. Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast. Quote:  6.5.16.1 Simple Assignment1. [...]— both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;[...] If it is allowed to see the returned value as the left operand, then implicit conversion of const T* to T* is not allowed. skim skim skim ... #### Share this post ##### Link to post ##### Share on other sites Quote:  What is the warning and what gcc version?The following produces no warnings using: gcc -ansi -pedantic -Wall -Wextra const_aware.c

AFAIK most recent stable. Didn't have extra warning options on, enabled them now, but with -stc=c99.

Anyway, the new warning message imply I messed something else up, and it's not the fault of the compiler.

Quote:
 Unfortunately not, array elements are not member pointers or references.

Ok, well it explained the first question. ;) You already more or less explained the second one.

Anyway, I've decided to stay away from const in the cases where anything might be modified by the use of a pointer to const object (even if indirectly through a member pointer of that object where the language allows this). Thanks for the help clearing this up!

And the case of the array was just bad programming at my part...

##### Share on other sites
Meh, even with "-Wall -Wextra -pedantic -std=c99", I fail to get an error. Maybe gcc is wrong, or the standard really allows implicit conversions like "const T* -> void*- > T*".

##### Share on other sites
Quote:
 Original post by CmpDevThe following produces no warnings using:\$ gcc -ansi -pedantic -Wall -Wextra const_aware.c*** Source Snippet Removed ***

Minor nitpick: -ansi is the same as -std=c89, even in the current GCC 4.4.

##### Share on other sites
Quote:
 Original post by Beyond_RepairOk, well it explained the first question.

Ah okay, sorry :D

Quote:
 Thanks for the help clearing this up!

No problem :)

##### Share on other sites
Quote:
 Original post by phresnelMeh, even with "-Wall -Wextra -pedantic -std=c99", I fail to get an error. Maybe gcc is wrong, or the standard really allows implicit conversions like "const T* -> void*- > T*".

There are not type conversions happening here. The const which makes pointer to constant structure does not make the data pointed to by the pointer inside the structure constant.

Quote:
 Minor nitpick: -ansi is the same as -std=c89, even in the current GCC 4.4.

Yes I know but c99 is not fully supported and ansi with pedantic is required for some extra checking.

[Edited by - CmpDev on May 4, 2009 11:26:25 AM]

##### Share on other sites
Quote:
Original post by CmpDev
Quote:
 Original post by phresnelMeh, even with "-Wall -Wextra -pedantic -std=c99", I fail to get an error. Maybe gcc is wrong, or the standard really allows implicit conversions like "const T* -> void*- > T*".

There are not type conversions happening here. The const which makes pointer to constant structure does not make the data pointed to by the pointer inside the structure constant.

Heh, glad to see that yet another poster mixed up the two OP cases (like myself), as I was really digging on the second example (somestruct_t* return_something(const somestruct_t* array, int index)).

##### Share on other sites
Quote:
 Original post by Beyond_RepairWhat gives in these cases? I thought that const implies I can't write directly in the type qualified

It looks to me that the type qualified is a pointer. So as long as you're not modifying the pointer, you're o.k. If the struct member modified in do_something is declared const, then you'd have a problem. And if you really needed to modify that member, typecasting that member as a non const might mollify your compiler.

##### Share on other sites
Quote:
Original post by phresnel
Quote:
Original post by CmpDev
Quote:
 Original post by phresnelMeh, even with "-Wall -Wextra -pedantic -std=c99", I fail to get an error. Maybe gcc is wrong, or the standard really allows implicit conversions like "const T* -> void*- > T*".

There are not type conversions happening here. The const which makes pointer to constant structure does not make the data pointed to by the pointer inside the structure constant.

Heh, glad to see that yet another poster mixed up the two OP cases (like myself), as I was really digging on the second example (somestruct_t* return_something(const somestruct_t* array, int index)).

Hmm I did miss that was your point, but in the snippet I posted I corrected that. gcc does give a warning about it and changing the data pointed to by the pointer is undefined, this is why gcc is warning.
The one quote which you did miss is the following which allows it, but it is an accident waiting to happen:
Quote:
 6.5.16.1 Simple assignmentConstraints1 One of the following shall hold:93)— the left operand has qualified or unqualified arithmetic type and the right has arithmetic type;— the left operand has a qualified or unqualified version of a structure or union type compatible with the type of the right;— both operands are pointers to qualified or unqualified versions of compatible types,and the type pointed to by the left has all the qualifiers of the type pointed to by theright;— one operand is a pointer to an object or incomplete type and the other is a pointer to aqualified or unqualified version of void, and the type pointed to by the left has allthe qualifiers of the type pointed to by the right; or— the left operand is a pointer and the right is a null pointer constant.— the left operand has type _Bool and the right is a pointer.

##### Share on other sites
Quote:
Original post by CmpDev
Quote:
Original post by phresnel
Quote:
Original post by CmpDev
Quote:
 Original post by phresnelMeh, even with "-Wall -Wextra -pedantic -std=c99", I fail to get an error. Maybe gcc is wrong, or the standard really allows implicit conversions like "const T* -> void*- > T*".

There are not type conversions happening here. The const which makes pointer to constant structure does not make the data pointed to by the pointer inside the structure constant.

Heh, glad to see that yet another poster mixed up the two OP cases (like myself), as I was really digging on the second example (somestruct_t* return_something(const somestruct_t* array, int index)).

Hmm I did miss that was your point, but in the snippet I posted I corrected that. gcc does give a warning about it and changing the data pointed to by the pointer is undefined, this is why gcc is warning.
The one quote which you did miss is the following which allows it, but it is an accident waiting to happen:
Quote:
 6.5.16.1 Simple assignmentConstraints1 One of the following shall hold:93)— the left operand has qualified or unqualified arithmetic type and the right has arithmetic type;— the left operand has a qualified or unqualified version of a structure or union type compatible with the type of the right;— both operands are pointers to qualified or unqualified versions of compatible types,and the type pointed to by the left has all the qualifiers of the type pointed to by theright;— one operand is a pointer to an object or incomplete type and the other is a pointer to aqualified or unqualified version of void, and the type pointed to by the left has allthe qualifiers of the type pointed to by the right; or— the left operand is a pointer and the right is a null pointer constant.— the left operand has type _Bool and the right is a pointer.

Interesting. Thanks.

I have mailed the GCC-help mailing list. Andrew Haley of redhat answered the following:

Quote:
 Andrew HaleyOne thing that you may have missed is that the standard doesn't sayanything about warnings or errors. When it says a translator mustissue a diagnostic, then that can be either a warning or an error.

The whole thread can be found here: http://gcc.gnu.org/ml/gcc-help/2009-05/msg00022.html.

I am going to ref your post.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
627749
• Total Posts
2978912

• 10
• 10
• 21
• 14
• 14