Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Typecasting pointers

4 views
Skip to first unread message

Nishu

unread,
Jan 29, 2007, 4:51:39 AM1/29/07
to
Hi All,

Is it valid in C to typecast a pointer?

eg. code snippet... considering int as 16 bit and long as 32 bit.

int *variable, value;

*((long*)variable)++ = value;
*((long*)variable)++ = value;
*((long*)variable)++ = value;
*((long*)variable)++ = value;

Thanks,
Nishu

Harald van Dijk

unread,
Jan 29, 2007, 4:59:11 AM1/29/07
to
Nishu wrote:
> Hi All,
>
> Is it valid in C to typecast a pointer?

If alignment requirements are met, then yes. However, with a few
exceptions, all you are allowed to do with the result is convert it
back to the original type.

> eg. code snippet... considering int as 16 bit and long as 32 bit.
>
> int *variable, value;
>
> *((long*)variable)++ = value;
> *((long*)variable)++ = value;
> *((long*)variable)++ = value;
> *((long*)variable)++ = value;

This is not allowed. Even when you are able to convert 'variable' to a
pointer-to-long, you may not use this pointer to access anything that
isn't really a long.

Nishu

unread,
Jan 29, 2007, 5:16:29 AM1/29/07
to

On Jan 29, 2:59 pm, "Harald van Dijk" <true...@gmail.com> wrote:
> Nishu wrote:
> > Hi All,
>

> > Is it valid in C to typecast a pointer?If alignment requirements are met, then yes. However, with a few


> exceptions, all you are allowed to do with the result is convert it
> back to the original type.
>
> > eg. code snippet... considering int as 16 bit and long as 32 bit.
>
> > int *variable, value;
>
> > *((long*)variable)++ = value;
> > *((long*)variable)++ = value;
> > *((long*)variable)++ = value;
> > *((long*)variable)++ = value;This is not allowed. Even when you are able to convert 'variable' to a
> pointer-to-long, you may not use this pointer to access anything that
> isn't really a long.

In case value is long...
long value;

I'm getting warnings on my compiler.."objects that have been cast are
not l-value."

Thanks,
Nishu

Ben Bacarisse

unread,
Jan 29, 2007, 5:52:04 AM1/29/07
to
"Nishu" <naresh...@gmail.com> writes:

Take out the UB caused by the cast to long * by replacing it with int *
and you should get the same message. It describes exactly and
succinctly what is wrong. The result of a cast is not an lvalue -- it
never denotes an object that can be changed. In your case,

*((int *)variable)++

would try to increment something, but the result of a cast is never a
thing that can be incremented, no matter what the type is used in the
cast. You should get the message from the more obvious:

int x;
((int)x)++; /* error... casts do not make lvalues */

--
Ben.

Chris Dollin

unread,
Jan 29, 2007, 5:59:49 AM1/29/07
to
Nishu wrote:

> Is it valid in C to typecast a pointer?

Aside: it's not "typecast". It's just "cast".

--
Chris "electric hedgehog" Dollin
"Who do you serve, and who do you trust?" /Crusade/

Richard Heathfield

unread,
Jan 29, 2007, 6:18:01 AM1/29/07
to
Nishu said:

> Hi All,
>
> Is it valid in C to typecast a pointer?

It's rarely wise, and often not valid.

> eg. code snippet... considering int as 16 bit and long as 32 bit.
>
> int *variable, value;
>
> *((long*)variable)++ = value;

Let's count the problems.

Firstly, value is indeterminate, so you can't use its value legitimately.
The behaviour is undefined if you try.

Secondly, even if that weren't a problem, variable is indeterminate, so you
can't use its value legitimately. The behaviour is undefined if you try.

Thirdly, even if those weren't problems, variable is an int *, and (if its
value isn't indeterminate or a null pointer) it points to an int object,
which may not be aligned correctly for a long int.

Fourthly, even if those weren't problems, a cast-expression such as
(long *)variable yields a value, not an object, and you can't use ++ on a
mere value. It requires an object.

Sort out those problems and then ask again.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.

Nishu

unread,
Jan 29, 2007, 6:46:36 AM1/29/07
to

On Jan 29, 4:18 pm, Richard Heathfield <r...@see.sig.invalid> wrote:
> Nishu said:
>
> > Hi All,
>

> > Is it valid in C to typecast a pointer?It's rarely wise, and often not valid.


>
> > eg. code snippet... considering int as 16 bit and long as 32 bit.
>
> > int *variable, value;
>
> > *((long*)variable)++ = value;Let's count the problems.
>

> Sort out those problems and then ask again.

Hi,
I want to cast my 16bit pointer as 32 bit pointer for copying
operation, after that i need 16bit pointer operations only. here's the
test version of what I need to do..

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
unsigned short value;
long lvalue;

short *ptr, *ptr1;

ptr = (short*) malloc(sizeof(short) * 8);

ptr1 = ptr;
value = 0xFFF0;

lvalue = (unsigned short)value | ((unsigned short)value << 16);

*((long*)ptr)++ = lvalue; /* is it portable? */
*((long*)ptr)++ = lvalue;
*((long*)ptr)++ = lvalue;
*((long*)ptr)++ = lvalue;

free (ptr1);
return 0;
}


MSVC doesn't give error here, but I'm doubtful about its portability.
Please help me about other possible loop holes too.

Thanks,
Nishu

Nishu

unread,
Jan 29, 2007, 6:54:39 AM1/29/07
to

On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:
>Hi,
> I want to cast my 16bit pointer as 32 bit pointer for copying
> operation, after that i need 16bit pointer operations only. here's the
> test version of what I need to do..
>

here's lil' correction... and one more doubt.

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
short value; /* it is signed actually*/
long lvalue;

short *ptr, *ptr1;

ptr = malloc(sizeof(short) * 8);

ptr1 = ptr;
value = 0xFFF0; /* i get warning here. I don't understand why.
warning is
'=' : truncation from 'const int ' to 'short' */

lvalue = (unsigned short)value | ((unsigned short)value << 16);

*((long*)ptr)++ = lvalue;


*((long*)ptr)++ = lvalue;
*((long*)ptr)++ = lvalue;
*((long*)ptr)++ = lvalue;

free (ptr1);
return 0;
}

Thanks,
Nishu

Chris Dollin

unread,
Jan 29, 2007, 7:13:43 AM1/29/07
to
Nishu wrote:

> On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:
>>Hi,
>> I want to cast my 16bit pointer as 32 bit pointer for copying
>> operation,

/Why/ do you want to do this bizarre thing?

>> after that i need 16bit pointer operations only. here's the
>> test version of what I need to do..
>>
>
> here's lil' correction... and one more doubt.
>
> #include<stdio.h>
> #include<stdlib.h>
>
> int main(void)
> {
> short value; /* it is signed actually*/
> long lvalue;
>
> short *ptr, *ptr1;
>
> ptr = malloc(sizeof(short) * 8);

Better is likely to be:

ptr = malloc( 8 * sizeof( *ptr ) );

If you want 8 things. (Below, it looks like you might really
want 4).

> ptr1 = ptr;
> value = 0xFFF0; /* i get warning here. I don't understand why.
> warning is
> '=' : truncation from 'const int ' to 'short' */

Well, yes. You say your `short`s are 16 bits. 0xFFF0 is a positive
value (there are no negative literals),and it's an `int`. It won't fit
into a signed short. Your compiler is warning you that you're trying
to stuff an `int` into a `short` and that you may well have lost
information. (Opinions about the values of such a message vary.)

> lvalue = (unsigned short)value | ((unsigned short)value << 16);

Why not declare `value` as an `unsigned short`, since that's all you
ever use it as? Come to that, why not assign a literal directly to
`lvalue` and not bother with `value` at all?

> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;

Similarly, if what you want to do is assign to successive `long`s
starting at the mallocated address, why not do the obvious, which
is

long *ptr = malloc( 4 * sizeof( *ptr ) );
...
*ptr++ = lvalue;
*ptr++ = lvalue;
*ptr++ = lvalue;
*ptr++ = lvalue;

or even (having declared `int i`):

for (i = 0; i < 4; i += 1) ptr[i] = lvalue;

> free (ptr1);
> return 0;
> }

I don't think you're telling us everything you need to.

--
Chris "electric hedgehog" Dollin

"It took a very long time, much longer than the most generous estimates."
- James White, /Sector General/

Kelly

unread,
Jan 29, 2007, 9:21:30 AM1/29/07
to
1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>Compiling...
1>test.c
1>c:\visual studio 2005\projects\test\test\test.c(43) : warning C4213:
nonstandard extension used : cast on l-value
1>c:\visual studio 2005\projects\test\test\test.c(44) : warning C4213:
nonstandard extension used : cast on l-value
1>c:\visual studio 2005\projects\test\test\test.c(45) : warning C4213:
nonstandard extension used : cast on l-value
1>c:\visual studio 2005\projects\test\test\test.c(46) : warning C4213:
nonstandard extension used : cast on l-value
1>c:\visual studio 2005\projects\test\test\test.c(43) : *warning C6011:
Dereferencing NULL pointer '((long *)ptr)++': Lines: 29, 30, 32, 34, 36,
37, 41, 43*

Looks ominous to me!

1>Linking...
1>Embedding manifest...
1>Test - 0 error(s), 5 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Keith Thompson

unread,
Jan 29, 2007, 4:07:34 PM1/29/07
to
"Nishu" <naresh...@gmail.com> writes:
> On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:
> > I want to cast my 16bit pointer as 32 bit pointer for copying
> > operation, after that i need 16bit pointer operations only. here's the
> > test version of what I need to do..
> >
>
> here's lil' correction... and one more doubt.

Ok, I think I see what you're trying to do. You want to create an
array of shorts, and initialize them all to the same value. If it
were an array of bytes memset() would be just the thing, but there's
no standard routine that does for shorts what memset() does for bytes.

You're assuming that short is 16 bits and long is 32 bits. Be aware
that these assumptions are *not* portable. If you're willing to live
with the fact that your code will break, perhaps quietly, on some
systems, you should at least document your assumptions.

> #include<stdio.h>
> #include<stdlib.h>
>
> int main(void)
> {
> short value; /* it is signed actually*/

Why is it signed? For what you're doing, using unsigned types would
be simpler -- ahd the value 0xFFF0 won't fit into a 16-bit unsigned
object.

> long lvalue;

"lvalue" turns out to be a poor name for this variable. I understand
that you meant it to be an abbreviation for "long value", but in C the
term "lvalue" has a specific meaning (roughly, it's an expression that
designates an object).

> short *ptr, *ptr1;

Again, unsigned short would probably serve your purposes better.

> ptr = malloc(sizeof(short) * 8);

Thank you for not casting the result of malloc(), but an even better
way to write this is:

ptr = malloc(8 * sizeof *ptr);

And you should *always* check the result of malloc().

> ptr1 = ptr;

You're saving the value of ptr so you can free() it later. That's
good, but see below for a comment on this.

> value = 0xFFF0; /* i get warning here. I don't understand why.
> warning is
> '=' : truncation from 'const int ' to 'short' */

The maximum value of signed short on your system is 0x7FFF; that's
what your compiler is warning you about.

> lvalue = (unsigned short)value | ((unsigned short)value << 16);

If you declare value as an unsigned short, you don't need the casts.

> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;
> *((long*)ptr)++ = lvalue;

This is the core of what you're doing, and of your problem.

You're initializing an array of 2-byte integers, but you're trying to
do it 4 bytes at a time, presumably because you think it will be
faster (more on that later). In general, this is a dangerous thing to
do, because there's no guarantee that an array of shorts will be
properly aligned as an array of longs. In this case, you happen to be
ok, because malloc() returns a result suitably aligned for any type.
If you're thinking of using this as a general technique, alignment
will eventually come back and bite you. You should also think about
the case where the length of the array is odd.

The "++" operator modifies an object. It can't be applied to
something that isn't an object -- specifically, it requires an lvalue,
an expression that designates an object. A cast yields a converted
*value*; it doesn't refer to any object. So applying "++" to the
result of a cast makes no more sense than assigning to the result of
"+":

int x;
(x + 2) = 4; /* illegal, (x + 2) is not an lvalue */

(The language *could* conceivably have defined reasonable semantics
for treating the result of a cast as an lvalue, but it didn't, and
we're stuck with that.)

A pointer increment advances the pointer by one object size,
specifically the size of the object to which it points. You want to
advance ptr by the size of a long, but it's declared to point to a
short. Casting the pointer *value* and incrementing it is, as
discussed above, illegal.

What you really want to do is take the value of ptr (of type short*),
convert it to long*, add 1 to the resulting *value*, and convert the
result back to short*:
ptr = (short*)((long*)ptr + 1);
Or you can just use the knowledge (well, assumption) that a long is
twice the size of a short, and simply do this:
ptr += 2;

Now this isn't something you can easily do as a side effect of your
assignment statement, but so what? Extreme terseness isn't always a
virtue. Do the assignment, then increment the pointer:

*((long*)ptr) = lvalue;
ptr += 2;
*((long*)ptr) = lvalue;
ptr += 2;
*((long*)ptr) = lvalue;
ptr += 2;
*((long*)ptr) = lvalue;

And we've dropped the final increment, since we're not using the value
of ptr again.

> free (ptr1);
> return 0;
> }

An outline of what you've done with memory allocation is:

ptr = malloc(...);
ptr1 = ptr;
/* manipulate ptr */
free(ptr1);

This is perfectly correct, but just as a matter of style you might
consider manipulating the *copy* of ptr rather than ptr itself. This
makes for greater symmetry (ptr = malloc(...); ... free(ptr);). You
can even declare ptr as const to make (reasonably) sure you don't
accidentally clobber it.

Now let's zoom back and look at what you're trying to do.

Except in performance-critical code, it's usually best to write the
most straightforward possible code, and let the compiler optimize it
as well as it can. In your program, you write a considerable amount
of extra code to initialize your array 4 bytes at a time rather than 2
bytes at a time, and you've unrolled the initialization loop (writing
four separate assignments rather than a single one in a loop). Either
or both of these *might* make your code a little faster -- or they
might not. By making your code more complex, you may have made it
more difficult for the optimizer to analyze; conceivably a good
optimizing compiler could have done a better job than you have. And,
by trying to be fancy, you've gotten the code wrong, which has cost
you many orders of magnitude more of your own time than the CPU time
you might have saved.

Once you get your code working, try measuring the *actual* time spent;
you may find that the improvement is either nonexistent, or just not
worth the effort.

Or you just might find that it's significant, that the code is in an
inner loop in a performance-critical application, and that this was
all worth it. Or it could be worthwhile just as a learning
experience.

If you do want to do this optimization, there are easier ways to go
about it. You can treat the whole array as an array of unsigned longs
and initialize it that way, rather than converting pointers on each
iteration.

Here's a simplified version of your program. I've removed the
optimizations, but I've added some error checking.
================================
#include <stdio.h> /* This isn't actually used */
#include <stdlib.h>
int main(void)
{
#define COUNT 8
#define INIT 0xFFF0

unsigned short value;
unsigned short *const ptr = malloc(COUNT * sizeof *ptr);
int i;

if (ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}

for (i = 0; i < COUNT; i ++) {
ptr[i] = INIT;
}

free (ptr);
return 0;
}
================================

And here's another version with optimization. I've unrolled the loop
as you did, and I've used a pointer rather than an integer index to
access the array. (It's tempting to assume that pointer accesses will
be faster than indexing, but it's not necesarily the case -- and an
optimizing compiler can often tranform one to the other.)

One note here. I've defined COUNT as a macro rather than using the
"magic number" 8. The idea is that you can change the definition of
COUNT if necessary without touching the rest of the program. For the
unoptimized version above, that works. For the optimized version
below, it doesn't; the number of assignment statements needs to be
COUNT/2 (and COUNT needs to be even), but if you change the definition
of COUNT you also need to manually update the unrolled loop.

================================
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(void)
{
/*
* We require long to be twice the size of short.
* We'll check this with an assert(); if it's not the case,
* we don't even want the program to run.
*/

#define COUNT 8
#define INIT 0xFFF0
#define INIT_TWICE (((unsigned long)INIT << 16) | (unsigned long)INIT)

unsigned short value;
unsigned short *const ptr = malloc(COUNT * sizeof *ptr);
unsigned long *lptr;

assert(sizeof(short) * 2 == sizeof(long));

if (ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}

lptr = (unsigned long*)ptr;
*lptr++ = INIT_TWICE;
*lptr++ = INIT_TWICE;
*lptr++ = INIT_TWICE;
*lptr = INIT_TWICE;

free (ptr);
return 0;
}
================================

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

David T. Ashley

unread,
Jan 29, 2007, 4:52:38 PM1/29/07
to
"Nishu" <naresh...@gmail.com> wrote in message
news:1170064299.6...@s48g2000cws.googlegroups.com...

> Hi All,
>
> Is it valid in C to typecast a pointer?
>
> eg. code snippet... considering int as 16 bit and long as 32 bit.
>
> int *variable, value;
>
> *((long*)variable)++ = value;
> *((long*)variable)++ = value;
> *((long*)variable)++ = value;

In type-casting a pointer, all you do is change the way the compiler treats
it in two contexts:

a)Array indexing and incrementing/decrementing (the compiler has to know how
large the data pointed to is in order to know how to index or advance a
pointer).

b)Variable/structure references using the pointer.

Where program space is critical (small embedded work), one finds all sorts
of tricks with unions and pointers to get the compiler to behave in the
desired way.

But in a larger system (such as an x86 box), there really aren't any
contexts where one needs to do this. If you have to go that low ... better
to write certain modules in assembly-language than to abuse the compiler in
ways which may become invalid with a compiler version or platform change.

--
David T. Ashley (d...@e3ft.com)
http://www.e3ft.com (Consulting Home Page)
http://www.dtashley.com (Personal Home Page)
http://gpl.e3ft.com (GPL Publications and Projects)


Walter Roberson

unread,
Jan 29, 2007, 5:09:25 PM1/29/07
to
In article <YKCdnVqw8bIN8SPY...@giganews.com>,

David T. Ashley <d...@e3ft.com> wrote:

>In type-casting a pointer, all you do is change the way the compiler treats
>it in two contexts:

>a)Array indexing and incrementing/decrementing (the compiler has to know how
>large the data pointed to is in order to know how to index or advance a
>pointer).

>b)Variable/structure references using the pointer.

If the pointer is cast to a type with a stricter alignment requirement
and then cast back again, the twice-cast pointer need not be valid.
(However, if a pointer is cast to a type with the same strictness or
less strict alignment, it may be cast back and is promised to compare
equal to the original.)

We can see from this that the actual representation can
irreversibly change when a pointer is cast to another type.
There can also be changes to such things as base segment and
offset when a pointer is cast -- some systems allow multiple
representations for the same pointer.

All in all, it can get more complicated internally than you imply
by saying that "all you do is change the way the compiler treats
it in two contexts."

--
"No one has the right to destroy another person's belief by
demanding empirical evidence." -- Ann Landers

Keith Thompson

unread,
Jan 29, 2007, 6:35:14 PM1/29/07
to
"David T. Ashley" <d...@e3ft.com> writes:
> "Nishu" <naresh...@gmail.com> wrote in message
> news:1170064299.6...@s48g2000cws.googlegroups.com...
> > Is it valid in C to typecast a pointer?
> >
> > eg. code snippet... considering int as 16 bit and long as 32 bit.
> >
> > int *variable, value;
> >
> > *((long*)variable)++ = value;
> > *((long*)variable)++ = value;
> > *((long*)variable)++ = value;
>
> In type-casting a pointer, all you do is change the way the compiler treats
> it in two contexts:
>
> a)Array indexing and incrementing/decrementing (the compiler has to know how
> large the data pointed to is in order to know how to index or advance a
> pointer).
>
> b)Variable/structure references using the pointer.
[...]

Casting (not "type-casting") a pointer converts its value to some
specified type, yielding a value of the new type. For a
pointer-to-pointer conversion, the result may or may not be a valid,
depending on a number of factors, some defined by the standard, some
implementation-defined.

For example, converting an object pointer to type unsigned char*
always gives you a valid result (assuming the original value is valid)
and allows you to access the representation of the pointed-to object.

pete

unread,
Jan 29, 2007, 7:08:05 PM1/29/07
to
Walter Roberson wrote:

> If the pointer is cast to a type with a stricter alignment requirement
> and then cast back again, the twice-cast pointer need not be valid.

The first cast pointer need not be valid either.

char array[sizeof(int) + 1];

*(int *)(array + 1) = 0;

--
pete

David T. Ashley

unread,
Jan 29, 2007, 8:30:47 PM1/29/07
to
"Walter Roberson" <robe...@ibd.nrc-cnrc.gc.ca> wrote in message
news:eplral$364$1...@canopus.cc.umanitoba.ca...

> In article <YKCdnVqw8bIN8SPY...@giganews.com>,
> David T. Ashley <d...@e3ft.com> wrote:
>
> (However, if a pointer is cast to a type with the same strictness or
> less strict alignment, it may be cast back and is promised to compare
> equal to the original.)

Is that a personal observation or part of a standard?

Walter Roberson

unread,
Jan 29, 2007, 8:49:13 PM1/29/07
to
In article <VuudnXID9eUsAiPY...@giganews.com>,

David T. Ashley <d...@e3ft.com> wrote:
>"Walter Roberson" <robe...@ibd.nrc-cnrc.gc.ca> wrote in message
>news:eplral$364$1...@canopus.cc.umanitoba.ca...
>> In article <YKCdnVqw8bIN8SPY...@giganews.com>,
>> David T. Ashley <d...@e3ft.com> wrote:
>>
>> (However, if a pointer is cast to a type with the same strictness or
>> less strict alignment, it may be cast back and is promised to compare
>> equal to the original.)

>Is that a personal observation or part of a standard?

ANSI X.3-159

3.3.4 Cast Operators
[...]
A pointer to an object or incomplete type may be converted to
a pointer to a different object type or a different incomplete
type. The resulting pointer might not be valid if it is
improperly aligned for the type pointed to. It is guaranteed,
however, that a pointer to an object of a given alignment
may be converted to a pointer to an object of the same
alignment or a less strict alignment and back again; the result
shall compare equal to the original pointer. (An object
that has character type has the least strict alignment.)
--
If you lie to the compiler, it will get its revenge. -- Henry Spencer

David T. Ashley

unread,
Jan 29, 2007, 11:34:01 PM1/29/07
to
"Walter Roberson" <robe...@ibd.nrc-cnrc.gc.ca> wrote in message
news:epm86p$jj3$1...@canopus.cc.umanitoba.ca...

Interesting.

I've never seen a machine where simply casting a pointer to a more strict
alignment will cause it to change its value. The trouble usually begins
when you try to USE the casted pointer.

But interesting that the standard only makes guarantees in one direction.

Nishu

unread,
Jan 30, 2007, 12:33:18 AM1/30/07
to
On Jan 30, 2:07 am, Keith Thompson <k...@mib.org> wrote:

> "Nishu" <naresh.at...@gmail.com> writes:
> > On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:
> > > I want to cast my 16bit pointer as 32 bit pointer for copying
> > > operation, after that i need 16bit pointer operations only. here's the
> > > test version of what I need to do..
>
> > here's lil' correction... and one more doubt.
>

> And here's another version with optimization. I've unrolled the loop

Thank you Keith and all. I'll keep these things in mind.

Thanks,
Nishu

Walter Roberson

unread,
Jan 30, 2007, 1:20:30 AM1/30/07
to
In article <2J6dnYzE1v05VyPY...@giganews.com>,

David T. Ashley <d...@e3ft.com> wrote:
>>>"Walter Roberson" <robe...@ibd.nrc-cnrc.gc.ca> wrote in message
>>>news:eplral$364$1...@canopus.cc.umanitoba.ca...

>>>> (However, if a pointer is cast to a type with the same strictness or


>>>> less strict alignment, it may be cast back and is promised to compare
>>>> equal to the original.)

>Interesting.

>I've never seen a machine where simply casting a pointer to a more strict
>alignment will cause it to change its value. The trouble usually begins
>when you try to USE the casted pointer.

Suppose you are using a machine which has int pointers distinct
from char pointers -- e.g., (int *)0x00a5 refers to the 166'th
int location and (char *)0x00a5 refers to the 166'th char location.
Suppose further that sizeof(int) == 4 and that the memory fields
overlap, so (int *)0x00a5 is the same memory location as
(char *)(0x00a5*sizeof(int)) = (char *)0x0294. [According to some
previous postings, similar machines exist and are actually used.]

In this situation, to convert an int* to the less strict alignment, you
multiply the int* address by sizeof(int) to get the equivilent (char *)
address. If one then convers that (char *) back to (int *), divide the
(char *) memory address by sizeof(int) and (int *)0x00a5 is recovered.

Now try that the other way around, converting (char *)0x00a5 to
an (int *). Divide the (char *) memory address by sizeof(int)
to get (int *)0x0029; cast back by multiplying by sizeof(int)
to get (char *)0x00a4 . Oh-oh, that's not the original (char *) address!

Hence, casting a pointer can change its value, and casting to
a stricter alignment and back can result in something that doesn't
point to the original location.
--
Prototypes are supertypes of their clones. -- maplesoft

Bernhard Holzmayer

unread,
Jan 30, 2007, 1:38:52 AM1/30/07
to
Nishu wrote:


Minimalistic answer:
int *variable, value;

*( (int *)( ((long*)variable)++ )) = value;
*( (int *)( ((long*)variable)++ )) = value;
*( (int *)( ((long*)variable)++ )) = value;
*( (int *)( ((long*)variable)++ )) = value;

should work, provided that the address where variable points to,
has been initialized somewhere else.

Long answer:
Before assigning the value, the pointer should be cast back to the correct
type. (Implicit type propagation would do this for you, but that's not
desirable here.)

It will copy 'value' to four address locations with one int between,
which will not be updated. Only every 2nd address location will be written.
My guess: This is not what you want.

However, if you really intend this and would like to make this thing more
evident, you might want to use a structural method like this:

struct wr {
int a;
int b;
};
struct wr * variable; // again: memory must be defined somewhere!
int value;

now using
variable++>a = value;
variable++>a = value;
variable++>a = value;
variable++>a = value;

would result in the same effect, but is much more readable, avoids casts and
is much less error prone.

But keep in mind, that structures can contain additional management
components which aren't visible. So, the physical layout in memory might
differ or at least be machine dependent.

Bernhard

Richard Heathfield

unread,
Jan 30, 2007, 2:11:26 AM1/30/07
to
Bernhard Holzmayer said:

<snip>



> Minimalistic answer:
> int *variable, value;
>
> *( (int *)( ((long*)variable)++ )) = value;
> *( (int *)( ((long*)variable)++ )) = value;
> *( (int *)( ((long*)variable)++ )) = value;
> *( (int *)( ((long*)variable)++ )) = value;
>
> should work, provided that the address where variable points to,
> has been initialized somewhere else.

No, it shouldn't, partly because ((long*)variable)++ is incorrect. You can
only use ++ on objects, not values. Alignment problems remain, too. This is
the wrong solution all round.

Bernhard Holzmayer

unread,
Jan 30, 2007, 6:34:19 AM1/30/07
to
Richard Heathfield wrote:

>
> No, it shouldn't, partly because ((long*)variable)++ is incorrect. You can
> only use ++ on objects, not values. Alignment problems remain, too. This
> is the wrong solution all round.

Sorry, please explain this. Here's my understanding:

int * variable;

tells us that variable is a pointer, correct? -- So

variable++;
((int *)variable)++;

are the same correct increment command, since the (useless) cast
doesn't change anything. If this results in a valid pointer,

*((int *)variable++)
*((long *)variable++)

should both mean valid lvalues, so that the assignment should work.
However, if size of pointers aren't equal, the second line makes no sense.

gcc -Wall eats the first without any comment,
in the second it warns (as you did!), that
"result of cast expressions shouldn't be used as lvalues".

I agree, that all this casting is ugly and not necessary at all,
if not a very strange compiler would take advantage of it.

From the standard's view, however, I don't understand where it breaks any
rule:
cast result of a pointer should result in a pointer again.
And increment operation is permitted on pointers.
The result of the pointer incrementation is a pointer again.
So it can be dereferenced and the assignment should hold, too.

Where am I wrong?

Bernhard

Harald van Dijk

unread,
Jan 30, 2007, 6:38:10 AM1/30/07
to
Bernhard Holzmayer wrote:
> Richard Heathfield wrote:
>
> >
> > No, it shouldn't, partly because ((long*)variable)++ is incorrect. You can
> > only use ++ on objects, not values. Alignment problems remain, too. This
> > is the wrong solution all round.
>
> Sorry, please explain this. Here's my understanding:
>
> int * variable;
>
> tells us that variable is a pointer, correct? -- So
>
> variable++;
> ((int *)variable)++;
>
> are the same correct increment command, since the (useless) cast
> doesn't change anything.

No. The cast does change something: it stops the expression from being
an lvalue. You can compare it to (variable + 0)++ or to (&*variable)+
+. Neither of those will work.

Richard Tobin

unread,
Jan 30, 2007, 6:48:44 AM1/30/07
to
In article <epnafm$o8f$1...@news01.versatel.de>,
Bernhard Holzmayer <Holzmayer...@deadspam.com> wrote:

>variable++;
>((int *)variable)++;
>
>are the same correct increment command, since the (useless) cast
>doesn't change anything.

No, the second is not legal. A cast expression is not an lvalue.

>From the standard's view, however, I don't understand where it breaks any
>rule:
>cast result of a pointer should result in a pointer again.

Yes, it results in a pointer, but not an lvalue.

>And increment operation is permitted on pointers.

Only on pointers that are lvalues.

You can imagine what these expressions would mean if they were legal.
In fact at one point in the drafting of the original ANSI standard
they *were* legal, but this was changed.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.

Chris Dollin

unread,
Jan 30, 2007, 7:14:17 AM1/30/07
to
Bernhard Holzmayer wrote:

> Richard Heathfield wrote:
>
>> No, it shouldn't, partly because ((long*)variable)++ is incorrect. You can
>> only use ++ on objects, not values. Alignment problems remain, too. This
>> is the wrong solution all round.
>
> Sorry, please explain this. Here's my understanding:
>
> int * variable;
>
> tells us that variable is a pointer, correct? -- So
>
> variable++;
> ((int *)variable)++;
>
> are the same correct increment command, since the (useless) cast
> doesn't change anything.

Contrarywise: it changes a /variable/ into a /value/. You might as
well say of

(variable + 0)++;

that it was a correct increment command, since the (useless) addition
of 0 doesn't change anything.

You can argue (but not here, please) that the case /ought not/ to
have this effect, but in Standard C, it does.

--
Chris "electric hedgehog" Dollin

"I'm still here and I'm holding the answers" - Karnataka, /Love and Affection/

Bernhard Holzmayer

unread,
Jan 30, 2007, 9:33:45 AM1/30/07
to
Bernhard Holzmayer wrote:

> Sorry, please explain this.

Thanks for clarification.

Especially to Richard for pointing out that such things were legal at times
when I started to use C ... (> 15 years ago).

Bernhard

0 new messages