For Programmers: Free Programming Magazines  


Home > Archive > C > January 2007 > Typecasting pointers









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Typecasting pointers
Nishu

2007-01-29, 3:57 am

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

2007-01-29, 7:56 am

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

2007-01-29, 7:56 am



On Jan 29, 2:59 pm, "Harald van D=C4=B3k" <true...@gmail.com> wrote:
> Nishu wrote:
>
t, then yes. However, with a few[color=darkred]
> exceptions, all you are allowed to do with the result is convert it
> back to the original type.
>
>
>
en you are able to convert 'variable' to a[color=darkred]
> 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=20
not l-value."

Thanks,
Nishu

Ben Bacarisse

2007-01-29, 7:56 am

"Nishu" <naresh.attri@gmail.com> writes:

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

2007-01-29, 7:56 am

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?" /Crue/

Richard Heathfield

2007-01-29, 7:56 am

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

2007-01-29, 7:56 am



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


> 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

2007-01-29, 7:56 am



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

2007-01-29, 7:56 am

Nishu wrote:

> On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:

/Why/ do you want to do this bizarre thing?
[color=darkred]
>
> 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

2007-01-29, 6:56 pm

Nishu wrote:
>
> On Jan 29, 4:46 pm, "Nishu" <naresh.at...@gmail.com> wrote:
>
> 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 ==========
David T. Ashley

2007-01-29, 9:56 pm

"Walter Roberson" <roberson@ibd.nrc-cnrc.gc.ca> wrote in message
news:eplral$364$1@canopus.cc.umanitoba.ca...
> In article < YKCdnVqw8bIN8SPYnZ2dnUVZ_rSjnZ2d@giganew
s.com>,
> David T. Ashley <dta@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?

--
David T. Ashley (dta@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

2007-01-29, 9:56 pm

In article < VuudnXID9eUsAiPYnZ2dnUVZ_uKknZ2d@giganew
s.com>,
David T. Ashley <dta@e3ft.com> wrote:
>"Walter Roberson" <roberson@ibd.nrc-cnrc.gc.ca> wrote in message
>news:eplral$364$1@canopus.cc.umanitoba.ca...
[color=darkred]
>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

2007-01-30, 3:57 am

"Walter Roberson" <roberson@ibd.nrc-cnrc.gc.ca> wrote in message
news:epm86p$jj3$1@canopus.cc.umanitoba.ca...
> In article < VuudnXID9eUsAiPYnZ2dnUVZ_uKknZ2d@giganew
s.com>,
> David T. Ashley <dta@e3ft.com> wrote:
>
>
> 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 (dta@e3ft.com)
http://www.e3ft.com (Consulting Home Page)
http://www.dtashley.com (Personal Home Page)
http://gpl.e3ft.com (GPL Publications and Projects)


Nishu

2007-01-30, 3:57 am

On Jan 30, 2:07 am, Keith Thompson <k...@mib.org> wrote:
> "Nishu" <naresh.at...@gmail.com> writes:
>
>


> 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

Walter Roberson

2007-01-30, 3:57 am

In article < 2J6dnYzE1v05VyPYnZ2dnUVZ_qWvnZ2d@giganew
s.com>,
David T. Ashley <dta@e3ft.com> wrote:
[color=darkred]
[color=darkred]
>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

2007-01-30, 3:57 am

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

Richard Heathfield

2007-01-30, 3:57 am

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.
Bernhard Holzmayer

2007-01-30, 7:57 am

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

2007-01-30, 7:57 am

Bernhard Holzmayer wrote:
> Richard Heathfield wrote:
>
>
> 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

2007-01-30, 7:57 am

In article <epnafm$o8f$1@news01.versatel.de>,
Bernhard Holzmayer <Holzmayer.Bernhard@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

2007-01-30, 7:57 am

Bernhard Holzmayer wrote:

> Richard Heathfield wrote:
>
>
> 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

2007-01-30, 6:57 pm

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


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com