uchar -> void* -> uchar

R

rouble

Hi All,

Is it safe to store a uchar in a void* and then extract the uchar value
out of it again ?

My understanding is that the size of a void* should always be equal to
or greater than the size of a uchar. So, theoretically, this should be
safe. Please correct me if I am wrong.

I've got the following code that compiles (with warnings), and it also
works as desired.

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 b = (void*) a;
14 printf("\nb is %x\n", b);
15
16 c = (unsigned char) b;
17 printf("\nc is %c\n", c);
18 }

I get the following warnings, for obvious reasons:

~/strings #5 > gcc void.c
void.c: In function `main':
void.c:13: warning: cast to pointer from integer of different size
void.c:16: warning: cast from pointer to integer of different size

Is there anyway to get rid of these warnings (without using memcpy) ?

I rewrote the code as follows:

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 memcpy(&b, &a, sizeof(unsigned char));
14 printf("\nb is %x\n", b);
15
16 memcpy(&c, &b, sizeof(unsigned char));
17 printf("\nc is %c\n", c);
18 }

No warnings, and it works as before.

Are there any gotchas as to the safety or portability of this code ?

TIA,
rouble
 
F

forayer

rouble said:
Hi All,

Is it safe to store a uchar in a void* and then extract the uchar value
out of it again ?
Pointers store addresses in them. The following piece of code should
make things a bit more clearer:

int main()
{
unsigned char a='A', c;
void *b=NULL;

printf("sizeof(void *)=%d\n",sizeof(void *)); // 4
printf("sizeof(unsigned char)=%d\n",sizeof(unsigned char)); // 1

printf("a is %c(0x%x)\n",a,a); // A(0x41)
printf("b points to %p\n",b); // nil
memcpy(&b, &a, sizeof(unsigned char));
printf("now b points to %p\n",b); // (0x41) <- this is what you are
doing
memcpy(&c, &b, sizeof(unsigned char));
printf("c is %c(0x%x)\n",c,c); // A(0x41)
}
My understanding is that the size of a void* should always be equal to
or greater than the size of a uchar. So, theoretically, this should be
safe. Please correct me if I am wrong.
Although you are right about the size part, you cant make use of the
pointer in a manner that makes sense to use a pointer, i.e. address
0x41(or some other value that you assign) could be anything! Trying to
modify it (or even access it) might raise errors. It would be safer to
allocate space for an unsigned char using malloc, then put the value of
'a' in _that_ space, and then copy it from there to 'c'.

cheers,
forayer
 
N

Netocrat

rouble wrote:
Pointers store addresses in them. The following piece of code should
make things a bit more clearer:

Although you are right about the size part, you cant make use of the
pointer in a manner that makes sense to use a pointer,

From the tone of his post I gather that rouble understands this.

I'm no standards guru like many on this group are but it looks kosher to
me. I don't know if it's guaranteed that void* is always larger than uchar
but I'd be very surprised if it wasn't.
It would be safer to
allocate space for an unsigned char using malloc, then put the value of
'a' in _that_ space, and then copy it from there to 'c'.

Sure. But he's not asking for a safer or different way to do it, he seems
to understand that it's a quirky thing to do and simply wants to know
whether this quirky thing is standards-compliant.

Or perhaps I've wildly misread his post - you do realise that this is an
odd and unnecessary thing to be doing, right?
 
J

junky_fellow

rouble said:
Hi All,

Is it safe to store a uchar in a void* and then extract the uchar value
out of it again ?
Converting an integer to a pointer type is implementation defined.
And it is better to avoid this.
My understanding is that the size of a void* should always be equal to
or greater than the size of a uchar. So, theoretically, this should be
safe. Please correct me if I am wrong.
Since, pointers and integers may have different representation on
a particular implementation, size doesn't matter.
You are not guaranteed to get the same integer value back.

<snip>
 
P

Peter Nilsson

rouble said:
Hi All,

Is it safe to store a uchar in a void* and then extract the uchar
value out of it again ?

You haven't said _why_ you feel this is important?
My understanding is that the size of a void* should always be equal
to or greater than the size of a uchar.

It must be at least 1 byte.
So, theoretically, this should be safe. Please correct me if I am
wrong.
Gladly...

I've got the following code that compiles (with warnings), and it
also works as desired.

On your implementation perhaps.
3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 b = (void*) a;

This involves an implementation defined conversion.
14 printf("\nb is %x\n", b);
15
16 c = (unsigned char) b;

This also involves an implementation defined conversion and need
not yield the original value.
17 printf("\nc is %c\n", c);
18 }

I get the following warnings, for obvious reasons:

~/strings #5 > gcc void.c
void.c: In function `main':
void.c:13: warning: cast to pointer from integer of different size
void.c:16: warning: cast from pointer to integer of different size

Is there anyway to get rid of these warnings (without using
memcpy) ?

It would be better if you understood why the warnings were there
in the first place, rather than seek a method of removing them.

C programmers should not play Russian Roulette.
I rewrote the code as follows:

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 memcpy(&b, &a, sizeof(unsigned char));

Another way is...

* (unsigned char *) &b = a;
14 printf("\nb is %x\n", b);
15
16 memcpy(&c, &b, sizeof(unsigned char));

c = * (unsigned char *) &b;
17 printf("\nc is %c\n", c);
18 }

No warnings, and it works as before.

You can safely imprint any byte within an object, however the original
object becomes unspecified. [In other words, b becomes useless as a
void *.]

It all sounds like classic trap for young players...

I have a problem A. I think the solution is X but I can't make it
work. I'll ask how to do X.

You should be asking how to solve problem A.
 
M

Michael Mair

rouble said:
Hi All,

Is it safe to store a uchar in a void* and then extract the uchar value
out of it again ?

My understanding is that the size of a void* should always be equal to
or greater than the size of a uchar. So, theoretically, this should be
safe. Please correct me if I am wrong.

I've got the following code that compiles (with warnings), and it also
works as desired.

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 b = (void*) a;
14 printf("\nb is %x\n", b);
15
16 c = (unsigned char) b;
17 printf("\nc is %c\n", c);
18 }

See the explanations in other replies.
I get the following warnings, for obvious reasons:

~/strings #5 > gcc void.c
void.c: In function `main':
void.c:13: warning: cast to pointer from integer of different size
void.c:16: warning: cast from pointer to integer of different size

Is there anyway to get rid of these warnings (without using memcpy) ?

Yes, access b using an unsigned char*.
I.e.
unsigned char *p = (unsigned char *)&b;
*p = a;

Note: Even if a is not of type unsigned char, p has to be of type
unsigned char*; one then has to access a in the same way.
p = ((unsigned char *)&a);
I rewrote the code as follows:

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 memcpy(&b, &a, sizeof(unsigned char));
14 printf("\nb is %x\n", b);
ITYM: %p - everything else is not safe.
15
16 memcpy(&c, &b, sizeof(unsigned char));
17 printf("\nc is %c\n", c);
18 }

No warnings, and it works as before.

Are there any gotchas as to the safety or portability of this code ?

Yep. Copying a to the first byte of b might bring b into a trap
representation, so that b cannot be safely accessed.

There is no way around this. As long as you only access
*(unsigned char *)&b, you should be on the safe side, though.
I strongly discourage that.


Cheers
Michael
 
L

Lawrence Kirby

Hi All,

Is it safe to store a uchar in a void* and then extract the uchar value
out of it again ?

My understanding is that the size of a void* should always be equal to
or greater than the size of a uchar. So, theoretically, this should be
safe. Please correct me if I am wrong.

I've got the following code that compiles (with warnings), and it also
works as desired.

What was it you wanted it to do, what are you trying to achieve? Why is it
necessary to use a void * variable here?
3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 b = (void*) a;
14 printf("\nb is %x\n", b);
15
16 c = (unsigned char) b;
17 printf("\nc is %c\n", c);
18 }

I get the following warnings, for obvious reasons:

~/strings #5 > gcc void.c
void.c: In function `main':
void.c:13: warning: cast to pointer from integer of different size
void.c:16: warning: cast from pointer to integer of different size

Is there anyway to get rid of these warnings (without using memcpy) ?

Yes, you fix the code by not trying to cast an integer to a pointer and
back again. This isn't a meaningful operation in standard C.
I rewrote the code as follows:

3 int
4 main ()
5 {
6
7 unsigned char a = 'A';
8 void *b = NULL;
9 unsigned char c;
10
11 printf("\na is %c\n", a);
12
13 memcpy(&b, &a, sizeof(unsigned char)); 14 printf("\nb is
%x\n", b);
15
16 memcpy(&c, &b, sizeof(unsigned char)); 17 printf("\nc is
%c\n", c);
18 }

No warnings, and it works as before.

This works because the value is not converted to void * and back. It is
legitimate to treat any addressible object as an array of unsigned char
which is in effect what memcpy() does. It is not doing the same thing as
the casting version.
Are there any gotchas as to the safety or portability of this code ?

Yes, integer/pointer casting is inherently non-portable.

Lawrence
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top