473,396 Members | 1,676 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Typecasting pointers

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

Jan 29 '07 #1
26 12502
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.

Jan 29 '07 #2


On Jan 29, 2:59 pm, "Harald van Dijk" <true...@gmail.comwrote:
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

Jan 29 '07 #3
"Nishu" <na**********@gmail.comwrites:
On Jan 29, 2:59 pm, "Harald van Dijk" <true...@gmail.comwrote:
>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."
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.
Jan 29 '07 #4
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/

Jan 29 '07 #5
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.
Jan 29 '07 #6


On Jan 29, 4:18 pm, Richard Heathfield <r...@see.sig.invalidwrote:
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

Jan 29 '07 #7


On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.comwrote:
>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

Jan 29 '07 #8
Nishu wrote:
On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.comwrote:
>>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/

Jan 29 '07 #9
Nishu wrote:
>
On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.comwrote:
>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
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 ==========
Jan 29 '07 #10
"Nishu" <na**********@gmail.comwrites:
On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.comwrote:
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.
Jan 29 '07 #11
"Nishu" <na**********@gmail.comwrote in message
news:11**********************@s48g2000cws.googlegr oups.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 (dt*@e3ft.com)
http://www.e3ft.com (Consulting Home Page)
http://www.dtashley.com (Personal Home Page)
http://gpl.e3ft.com (GPL Publications and Projects)
Jan 29 '07 #12
In article <YK******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:
>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
Jan 29 '07 #13
"David T. Ashley" <dt*@e3ft.comwrites:
"Nishu" <na**********@gmail.comwrote in message
news:11**********************@s48g2000cws.googlegr oups.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.

--
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.
Jan 29 '07 #14
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
Jan 30 '07 #15
"Walter Roberson" <ro******@ibd.nrc-cnrc.gc.cawrote in message
news:ep**********@canopus.cc.umanitoba.ca...
In article <YK******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:

(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?

--
David T. Ashley (dt*@e3ft.com)
http://www.e3ft.com (Consulting Home Page)
http://www.dtashley.com (Personal Home Page)
http://gpl.e3ft.com (GPL Publications and Projects)
Jan 30 '07 #16
In article <Vu******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:
>"Walter Roberson" <ro******@ibd.nrc-cnrc.gc.cawrote in message
news:ep**********@canopus.cc.umanitoba.ca...
>In article <YK******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:

(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
Jan 30 '07 #17
"Walter Roberson" <ro******@ibd.nrc-cnrc.gc.cawrote in message
news:ep**********@canopus.cc.umanitoba.ca...
In article <Vu******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:
>>"Walter Roberson" <ro******@ibd.nrc-cnrc.gc.cawrote in message
news:ep**********@canopus.cc.umanitoba.ca...
>>In article <YK******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:

(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.)
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.

--
David T. Ashley (dt*@e3ft.com)
http://www.e3ft.com (Consulting Home Page)
http://www.dtashley.com (Personal Home Page)
http://gpl.e3ft.com (GPL Publications and Projects)
Jan 30 '07 #18
On Jan 30, 2:07 am, Keith Thompson <k...@mib.orgwrote:
"Nishu" <naresh.at...@gmail.comwrites:
On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.comwrote:
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
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;}
Thank you Keith and all. I'll keep these things in mind.

Thanks,
Nishu

Jan 30 '07 #19
In article <2J******************************@giganews.com>,
David T. Ashley <dt*@e3ft.comwrote:
>>>"Walter Roberson" <ro******@ibd.nrc-cnrc.gc.cawrote in message
news:ep**********@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
Jan 30 '07 #20
Nishu wrote:
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

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

Jan 30 '07 #21
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.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 30 '07 #22
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



Jan 30 '07 #23
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.

Jan 30 '07 #24
In article <ep**********@news01.versatel.de>,
Bernhard Holzmayer <Ho****************@deadspam.comwrote:
>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.
Jan 30 '07 #25
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/

Jan 30 '07 #26
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
Jan 30 '07 #27

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: brian | last post by:
Quick question: if I have a structure: struct foo { unsigned char *packet; unsigned char *ip_src; };
12
by: bwaichu | last post by:
What is the best way to handle this warning: warning: cast from pointer to integer of different size I am casting in and out of a function that requires a pointer type. I am casting an...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.