Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > casting const away

Reply
Thread Tools

casting const away

 
 
gwowen
Guest
Posts: n/a
 
      01-07-2011
On Jan 6, 5:47*am, "copx" <c...@gazeta.pl> wrote:
> In a situation like this
>
> void my_func(const FOO_T *);
>
> *foo = 'b';
> my_func(foo);
> putchar(*foo);
>
> Is the compiler allowed to replace the second foo->a with 'b'
> i.e. allowed to assume that my_func does indeed not modify
> foo?


Certainly not in general.

int x = 7;
void bar(const int*);
int main()
{
x = 7;
const int *p = &x;
bar(p); printf("%d\n",*p);
}

// Now in a separate translation unit...
extern int x;
void bar(const int* d)
{
// x can't be changed through p ... but
// x can still be changed
if(x==0) x = *d;
else x = 0;
return;
}

// What should this program print?
// Of course, in certain cases the compiler may be able to do alias
analysis and make the change, but not in general.
 
Reply With Quote
 
 
 
 
Kelsey Bjarnason
Guest
Posts: n/a
 
      01-07-2011
On Thu, 06 Jan 2011 11:53:23 +0100, copx wrote:

> "copx" wrote in message news:ig3l22$3hb$... Here's
> some compile-ready code which illustrates the issue:
>
> #include <stdio.h>
>
> void foo(const int *c)
> {
> *((int *)c) = 'B';
> }
>
>
> int main(void)
> {
> int a = 'A';
>
> foo(&a);
>
> putchar(a);
>
> return 0;
> }
>
>
> ====
> Result: no warnings, prints 'B';
>
> As I wrote in the other post I think I have figured it out already.


In this example, as you say, it appears to work, but I believe the key
term there is "appears to".

You've essentially lied to the compiler; telling it (where main calls
foo) that the value will not - indeed cannot - be modified, but then you
modify it.

AIUI, the compiler is free to believe what it's told - that the parameter
is, indeed, const and thus won't be modified. In a somewhat less trivial
example, it may well decide to stuff the value ('A') into a register,
then use that in passing the value to putchar, meaning that the
modifications you made in foo() have no effect on the value displayed -
even though the value of a itself may in fact have been modified.

Something like this (pseudo assembler):

load reg1, 'A'
load reg2, reg1 ; since the value won't be modified, cache it
store [a], reg1 ; assign to a
load reg1, @a ; get address of a into reg1
call foo,reg1 ; call foo with address of a, in reg1
load reg1, reg2 ; retrieve cached value
call putchar, reg1 ; use cached - original - value for putchar


The fact you are in essence lying to the compiler about what main can
expect to happen - or, rather, not happen - to a suggests to me the
compiler is free to do whatever it thinks is right - which may differ
from run to run, optimization to optimization, compiler to compiler, etc.

 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      01-07-2011
On 01/ 7/11 12:36 PM, Tim Rentsch wrote:
> Ian Collins<ian-> writes:
>
>> On 01/ 7/11 11:56 AM, Tim Rentsch wrote:
>>> Ian Collins<ian-> writes:
>>>
>>>> On 01/ 7/11 10:43 AM, copx wrote:
>>>>>
>>>>> The standard only says "through that pointer" notice the "that".
>>>>> I can copy the value of the const pointer to a non-const pointer
>>>>> and then use this newly created pointer to modify the object thus
>>>>> the object is never actually modified "through that pointer".
>>>>
>>>> Yes you can, but you have to lie to the compiler (cast) to do so.
>>>>
>>>>> The exact, literal meaning of what the standard says validates the
>>>>> behavior of GCC IMO, but the wording of the standard is so horribly
>>>>> confusing here that I wouldn't be surprised if other compilers interpret
>>>>> this mess in a different way.
>>>>
>>>> The wording is clear: once you lie to the compiler you are in the land
>>>> of undefined behaviour.
>>>
>>> It would be most helpful if you would post a response
>>> supporting these statements, citing those sections
>>> of the Standard that are pertinent.

>>
>> Maybe, but it's a lovely day and there's a beer with my name on it
>> down on the beach.
>>
>> While I'm away, consider the case where the address passed is in read
>> only memory.

>
> That circumstance hold in this case, as another posting from copx in
> this thread makes clear.


I was responding to the case he posted:

void foo(const int *c)
{
*((int *)c) = 'B';
}

> Certainly it is true that if a pointer to
> an object that was defined as const-qualified is casted and used to
> store then the resulting behavior is undefined.


Given the function above, there's no way (inside foo) of knowing whether
the original object was const-qualified or not.

> The question,
> however, is what happens when a pointer to a non-const-qualified
> object is converted to a pointer to a const-qualified type, which is
> subsequently converted back to the original type and then used to
> store. The behavior in such circumstances is well-defined, not
> undefined.


True. But that guarantee can't be met with a function parameter.

> The reasoning about casting being lying to the compiler
> is bogus; there is nothing wrong with this casting in the case
> under consideration.


That wasn't how I read it.

--
Ian Collins
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-07-2011
Ian Collins <ian-> writes:

> On 01/ 7/11 12:36 PM, Tim Rentsch wrote:
>> Ian Collins<ian-> writes:
>>
>>> On 01/ 7/11 11:56 AM, Tim Rentsch wrote:
>>>> Ian Collins<ian-> writes:
>>>>
>>>>> On 01/ 7/11 10:43 AM, copx wrote:
>>>>>>
>>>>>> The standard only says "through that pointer" notice the "that".
>>>>>> I can copy the value of the const pointer to a non-const pointer
>>>>>> and then use this newly created pointer to modify the object thus
>>>>>> the object is never actually modified "through that pointer".
>>>>>
>>>>> Yes you can, but you have to lie to the compiler (cast) to do so.
>>>>>
>>>>>> The exact, literal meaning of what the standard says validates the
>>>>>> behavior of GCC IMO, but the wording of the standard is so horribly
>>>>>> confusing here that I wouldn't be surprised if other compilers interpret
>>>>>> this mess in a different way.
>>>>>
>>>>> The wording is clear: once you lie to the compiler you are in the land
>>>>> of undefined behaviour.
>>>>
>>>> It would be most helpful if you would post a response
>>>> supporting these statements, citing those sections
>>>> of the Standard that are pertinent.
>>>
>>> Maybe, but it's a lovely day and there's a beer with my name on it
>>> down on the beach.
>>>
>>> While I'm away, consider the case where the address passed is in read
>>> only memory.

>>
>> That circumstance hold in this case, as another posting from copx in
>> this thread makes clear.

>
> I was responding to the case he posted:
>
> void foo(const int *c)
> {
> *((int *)c) = 'B';
> }


This function _must work_ if called with an argument of
type (int *) that is a valid (non-null) pointer (to an
object of type int). Do you agree?


>> Certainly it is true that if a pointer to
>> an object that was defined as const-qualified is casted and used to
>> store then the resulting behavior is undefined.

>
> Given the function above, there's no way (inside foo) of knowing
> whether the original object was const-qualified or not.


That's true, but even so the function foo() must work if
called with a pointer to a modifiable int object. It
doesn't have to work if called with a pointer to an object
defined as const-qualified, but it _does_ have to work if
called with a pointer to an object defined without const.

>> The question,
>> however, is what happens when a pointer to a non-const-qualified
>> object is converted to a pointer to a const-qualified type, which is
>> subsequently converted back to the original type and then used to
>> store. The behavior in such circumstances is well-defined, not
>> undefined.

>
> True. But that guarantee can't be met with a function parameter.


Indeed it can, and the function in question must be compiled
so that it will.

>> The reasoning about casting being lying to the compiler
>> is bogus; there is nothing wrong with this casting in the case
>> under consideration.

>
> That wasn't how I read it.


It would help if you could be a little more explicit in
saying just what interpretation you believe is actually
the case. I will start the ball rolling. The program
copx posted:

#include <stdio.h>

void foo(const int *c)
{
*((int *)c) = 'B';
}


int main(void)
{
int a = 'A';
foo(&a);
putchar(a);
return 0;
}

does _not_ have any undefined behavior. Do you dispute
that? If so, please cite those sections of the Standard
that support your view.
 
Reply With Quote
 
Marcin Grzegorczyk
Guest
Posts: n/a
 
      01-07-2011
Francis Moreau wrote:
> "christian.bau"<. uk> writes:
>
> [...]
>
>> For example:
>>
>> int i; const int* p =&i; * (int *) p = 1;
>>
>> is perfectly fine, but
>>
>>
>> const int i; const int* p =&i; * (int *) p = 1;
>>
>> is undefined behaviour. The first doesn't modify a const object, the
>> second one does. Use "const int* restrict" instead:
>>
>> int i; const int* restrict p =&i; * (int *) p = 1; // Undefined
>> behaviour

>
> Could you argument your last example ?
>
> I don't see why adding 'restrict' qualifier invokes undefined
> behaviour. For me, the cast is defined and the effective rules are
> respected.


The second sentence of 6.7.3.1p4 (Formal definition of restrict) says:
# If L is used to access the value of the object X that it designates,
# and X is also modified (by any means), then the following
# requirements apply: T shall not be const-qualified.
(and then it goes on to list the other requirements)

In that sentence, L is any lvalue that has &L derived (directly or
indirectly) from some restrict-qualified pointer.

Thus, a modification - by any means - of an object pointed to by a
restrict-qualified pointer to a const-qualified type causes undefined
behaviour, unless that object is never accessed using an expression
derived from the said restrict-qualified pointer (within the pointer's
lifetime).

I'm aware that 6.7.3.1 is not easy to understand, but once you get
though the terse wording, at least that point becomes pretty clear.
--
Marcin Grzegorczyk
 
Reply With Quote
 
Francis Moreau
Guest
Posts: n/a
 
      01-09-2011
"christian.bau" <> writes:

> On Jan 7, 7:55*am, Francis Moreau <francis.m...@gmail.com> wrote:
>
>> Could you argument your last example ?
>>
>> I don't see why adding 'restrict' qualifier invokes undefined
>> behaviour. For me, the cast is defined and the effective rules are
>> respected.

>
> That is _exactly_ one of the two situations that "restrict" was
> invented for: To tell the compiler that anything that is accessed
> through a const* restrict pointer is not going to be modified by any
> means at all, as long as the const* restrict pointer variable is in
> scope, to allow compiler optimisations. Otherwise, take this example:


Ok, I didn't know that usage of 'restrict'.

Actually I must admit that I tried a couple of time to read the formal
definition of 'restrict' and have never understood it: it's just a pain
to read and have always found something more interesting to do...

Sigh, need to fix this though.
--
Francis
 
Reply With Quote
 
Francis Moreau
Guest
Posts: n/a
 
      01-09-2011
Marcin Grzegorczyk <> writes:

> Francis Moreau wrote:
>> "christian.bau"<. uk> writes:
>>
>> [...]

>
>>
>>> For example:
>>>
>>> int i; const int* p =&i; * (int *) p = 1;
>>>
>>> is perfectly fine, but
>>>
>>>
>>> const int i; const int* p =&i; * (int *) p = 1;
>>>
>>> is undefined behaviour. The first doesn't modify a const object, the
>>> second one does. Use "const int* restrict" instead:
>>>
>>> int i; const int* restrict p =&i; * (int *) p = 1; // Undefined
>>> behaviour

>>
>> Could you argument your last example ?
>>
>> I don't see why adding 'restrict' qualifier invokes undefined
>> behaviour. For me, the cast is defined and the effective rules are
>> respected.

>
> The second sentence of 6.7.3.1p4 (Formal definition of restrict) says:
> # If L is used to access the value of the object X that it designates,
> # and X is also modified (by any means), then the following
> # requirements apply: T shall not be const-qualified.
> (and then it goes on to list the other requirements)
>
> In that sentence, L is any lvalue that has &L derived (directly or
> indirectly) from some restrict-qualified pointer.
>
> Thus, a modification - by any means - of an object pointed to by a
> restrict-qualified pointer to a const-qualified type causes undefined
> behaviour, unless that object is never accessed using an expression
> derived from the said restrict-qualified pointer (within the pointer's
> lifetime).
>
> I'm aware that 6.7.3.1 is not easy to understand, but once you get
> though the terse wording, at least that point becomes pretty clear.


I've never got it unfortunately.

BTW is there any documentation about restrict more readable (I mean with
simple sentences, examples with main points...) out there ?

Thanks.
--
Francis
 
Reply With Quote
 
copx
Guest
Posts: n/a
 
      01-10-2011


"Kelsey Bjarnason" wrote in message
newsr4jv7-...
>You've essentially lied to the compiler;


There is no such thing as "lying to the compiler" in ISO C.

> telling it (where main calls
>foo) that the value will not - indeed cannot - be modified, but then you
>modify it.


The meaning of "const" in ISO C is not defined by the English
word "constant" but only by the standard. The wording of
the standard does not support your claim.

Really, this next group has become almost useless. A few years
ago Richard Heathfield, Dan Pop, Lawrence Kirby, and
if necessary Steve Summit himself would have all agreed on what
the standard says, and thus the question would have been solved
with final authority.

I am sure that I am right, but of course so you are. This group
no longer has the necesary amount of universally respected,
active (and aggressive) C experts to decide such questions.
That we are still arguing about this is the proof.

c.l.c. with it's strict definition of what's on topic (i.e. if it's not
in the standard it's off-topic here) used to be good for exactly
one thing: answering questions like this with final authority.

Now that this trait is gone this group might as well disband.

Really, I don't come here for endless internet debates with
random nobodys (such as yourself) whose opinion is about
as relevant as my own.

Next time I will just try to figure out what the standard
says myself and don't even bother with this group. Such
endless arguing is just a waste of time.

 
Reply With Quote
 
gwowen
Guest
Posts: n/a
 
      01-10-2011
On Jan 9, 11:20*am, Francis Moreau <francis.m...@gmail.com> wrote:
> BTW is there any documentation about restrict more readable (I mean with
> simple sentences, examples with main points...) out there ?


I don't know how useful you'll find this:
http://cellperformance.beyond3d.com/...t-keyword.html
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-10-2011
"christian.bau" <> writes:

> On Jan 9, 11:20Â*am, Francis Moreau <francis.m...@gmail.com> wrote:
>> BTW is there any documentation about restrict more readable (I mean with
>> simple sentences, examples with main points...) out there ?

>
> 1. If an object is accessed using an lvalue based on a "const
> restrict*" pointer, and the same object is modified in any way,
> behaviour is undefined.
>
> 2. If an object is accessed or modified using an lvalue based on a
> "restrict*" pointer, and the same object is modified using an lvalue
> that is _not_ based on the same "restrict*" pointer, then behaviour is
> undefined.
>
> 3. If an object is modified using an lvalue based on a "restrict*"
> pointer, and the same object is accessed or modified using an lvalue
> that is _not_ based on the same "restrict*" pointer, then behaviour is
> undefined.
>
> To explain "based on" a simple example:
>
> int i;
> int restrict* p = &i;
> int* q = p;
> int* r = &i;
>
> The lvalue *q is "based on p" because it has been calculated using the
> address of p only (but not the value that p points to), but the
> lvalues i or *r are not "based on p". Basically the compiler is
> allowed to assume that reading or writing data through the pointer p
> and anything derived from it does _not_ interfere with reading or
> writing data through lvalues that are _not_ derived from p.


You've used "restrict*" in several places (hence the full quote) where
you should really have written "*restrict". In some cases, I don't
think you mean it to be C code, but even then it's at the least rather
confusing -- more so since you do write the same think when it clearly
is C code.

--
Ben.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
is const necessary in eg int compar(const void *, const void *) lovecreatesbeauty@gmail.c0m C Programming 26 11-10-2008 09:47 PM
const correctness - should C++ prefer const member over non-const? fungus C++ 13 10-31-2008 05:33 AM
Casting from const pair<const unsigned char*, size_t>* to constpair<unsigned char*, size_t>* Alex Vinokur C++ 9 10-13-2008 05:05 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM
Casting int'** to 'const int * const * const' dosn't work, why? Jonas.Holmsten@gmail.com C Programming 11 07-01-2007 06:16 PM



Advertisments