Typecasting Pointers on a 64 bit System

B

bwaichu

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 integer as a pointer, but the pointer is 8 bytes while
the integer is only 4 bytes.

Here's an example function:

pthread_create(&tid, NULL, readit, (void *)(long)connfd)

I need to pass the file descriptor as a void * for pthread_create. But
I
need the file descriptor as an integer to read and write to it. Is the
above the best approach to turn off the warning? I am considering just
typecasting to size_t before typecasting to the pointer. Is that a
better
approach than typecasting to long since size_t should remain equal to
the size of pointers?

Of course, I run into the reverse problem when I have to close the
file descriptor.

close((int) arg);

I don't even know what to do in the above case. I shouldn't be
truncating
anything, so I should be okay.

I originally wrote the code using a 32 bit version, so I am receiving
these errors
when I ported it over to a 64 bit version.

Thanks!
 
I

Ian Collins

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 integer as a pointer, but the pointer is 8 bytes while
the integer is only 4 bytes.

Here's an example function:

pthread_create(&tid, NULL, readit, (void *)(long)connfd)
Why cast rather than simply pass the address of the int?
 
D

Dann Corbit

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 integer as a pointer, but the pointer is 8 bytes while
the integer is only 4 bytes.

Here's an example function:

pthread_create(&tid, NULL, readit, (void *)(long)connfd)

I need to pass the file descriptor as a void * for pthread_create. But
I
need the file descriptor as an integer to read and write to it. Is the
above the best approach to turn off the warning? I am considering just
typecasting to size_t before typecasting to the pointer. Is that a
better
approach than typecasting to long since size_t should remain equal to
the size of pointers?

Of course, I run into the reverse problem when I have to close the
file descriptor.

close((int) arg);

I don't even know what to do in the above case. I shouldn't be
truncating
anything, so I should be okay.

I originally wrote the code using a 32 bit version, so I am receiving
these errors
when I ported it over to a 64 bit version.

If your pointer is 8 bytes and your integer is 4 bytes, then it is
physically impossible for the mapping to be one to one and onto. (Which is
another way of saying that such a transfer is clearly not reversible,
because you have lost one half of your address).

You may be able to store the pointer in a long long, but why not store it in
another pointer [preferably of the same type]? Another possibility is to
store it in a character string either by sprintf() for a human readable
version or by memcpy() into an array that is sizeof (void *) bytes long.

Aside:
You can't cram 8 pounds of hamburger into a 4 pound can. You'll have 4
pounds of burger on the floor. But if you can decompile it back into the
cow, you might have an interesting conversation starter.
 
E

Eric Sosman

What is the best way to handle this warning:

warning: cast from pointer to integer of different size

Best way: Don't Do That. Pointers are not integers, and
integers are not pointers, and trying to pretend they are the
same is not smart.
I am casting in and out of a function that requires a pointer type. I
am casting an integer as a pointer, but the pointer is 8 bytes while
the integer is only 4 bytes.

You are doing something that is not a good idea. Stop.
Here's an example function:

pthread_create(&tid, NULL, readit, (void *)(long)connfd)

I need to pass the file descriptor as a void * for pthread_create. But
I
need the file descriptor as an integer to read and write to it. Is the
above the best approach to turn off the warning? I am considering just
typecasting to size_t before typecasting to the pointer. Is that a
better
approach than typecasting to long since size_t should remain equal to
the size of pointers?

Pass a pointer to the integer variable:

pthread_create(..., &connfd);
Of course, I run into the reverse problem when I have to close the
file descriptor.

close((int) arg);

... and on the other end (threads are off-topic here, but
we'll let that pass), convert the void* back to an int* and
use it to retrieve the actual int value:

close (* (int*)arg );

Note that the conversion of int* to void* and back to int*
again is a completely different matter from what you've been
trying. This pointer-to-pointer conversion is well-defined;
the pointer-integer-pointer conversion is not.
I don't even know what to do in the above case. I shouldn't be
truncating
anything, so I should be okay.

Yes, of course: You're perfectly okay. That's why the
compiler is applauding your attempt. ;-)
I originally wrote the code using a 32 bit version, so I am receiving
these errors
when I ported it over to a 64 bit version.

It was bad even in thirty-two bits. Now it's worse.
 
C

Chris Torek

pthread_create(&tid, NULL, readit, (void *)(long)connfd)

(where the fourth argument to pthread_create() has type "void *",
and "connfd" is an "int")
I need to pass the file descriptor as a void * for pthread_create.

Well, not quite. You do need to pass a "void *" -- but there is
nothing that says you have to take the "int" value, convert it
to "void *", and then pass that. You can, instead, pass the
address of a data structure that includes the desired "int"
value.

For instance:

struct data_to_pass_via_pthread_create {
int this;
double that;
long the_other;
int connfd;
};
...
struct data_to_pass_via_pthread_create x;
x.connfd = connfd;
...
result = pthread_create(&tid, NULL, readit, &x);
...

If the only data item you want to pass is "connfd" itself, just
ues &connfd instead of setting up some object "x" and using &x.

Note that the lifetime (i.e., storage duration) of the variable
you pass via this pointer needs to be sufficiently great so that
wherever you access the pointer -- presumably in a POSIX thread,
about which we in comp.lang.c cannot know anything :) -- that
pointer is still valid. (What this really means is that, because
POSIX threads do funny stack manipulation, using "auto" variables
is sometimes suspect -- you may have to use "static" variables
or use malloc() to get sufficient lifetimes.)

(When you used the "sleazy hack" of converting the integer directly
to (void *) via cast, and then back via another cast, in the 32-bit
version, you avoided the need to make sure that the object to which
the pointer points remained valid, because the pointer did not in
fact point to any object. When you switch to the "fully portable"
method of passing the address of an object, the lifetime of the
object starts to matter.)
 
B

bwaichu

Thanks.

This worked a whole lot better:

close(*(int *)arg);

Thanks alot! And just passing the address of the file descriptor
worked out great.

Brian

Note: I knew this was bad to start with it. But I had overlooked the
obvious pointer to
pointer conversion since I did not receive any warnings on the
32 bit OS. Also,
my question had absolutely nothing to do with threads. It
just happened to be
the scenario that was causing me to see warnings pop up when I
compiled on my 64
bit OS.
 
B

bwaichu

Chris said:
(When you used the "sleazy hack" of converting the integer directly
to (void *) via cast, and then back via another cast, in the 32-bit
version, you avoided the need to make sure that the object to which
the pointer points remained valid, because the pointer did not in
fact point to any object. When you switch to the "fully portable"
method of passing the address of an object, the lifetime of the
object starts to matter.)

And I wanted to fix the above problem before proceeding to write code
that parses the string that I read in that thread.

Here's a compiler specific question:

Is there any gcc compiler flag I can use that would have warned me
about this on my 32 bit OS? (I am currently using -O -Wall -pedantic
-ansi -pthread; C99 as far as I know isn't fully supported on gcc
3.3.5.)

Now, back to C specific questions:

What would cause me to lose the object? At this point I am only
passing a file descriptor, but I can foresee in the future passing
structures as I work through this little program.

Thanks,

Brian
 
R

Richard Heathfield

(e-mail address removed) said:

Is there any gcc compiler flag I can use that would have warned me
about this on my 32 bit OS?

Very unlikely.

When you cast, you're saying to the compiler, "trust me, I know what I'm
doing, I won't hurt you, it'll be all right"; and the compiler looks
lovingly into your eyes, and *believes* you - even when it does actually
hurt quite a bit - and doesn't say a word.

Most of the time, alas, the compiler's trust is misplaced, because most of
the time the programmer is untrustworthy, and doesn't know what he's doing.
And it most certainly won't be all right.
 
E

Eric Sosman

Thanks.

This worked a whole lot better:

close(*(int *)arg);

Thanks alot! And just passing the address of the file descriptor
worked out great.

Brian

Note: I knew this was bad to start with it. But I had overlooked the
obvious pointer to
pointer conversion since I did not receive any warnings on the
32 bit OS. Also,
my question had absolutely nothing to do with threads. It
just happened to be
the scenario that was causing me to see warnings pop up when I
compiled on my 64
bit OS.

<off-topic>

One cautionary note: Whenever you pass a pointer to an
asynchronously-executing thread -- at thread creation or at
any other time -- you must take care that the pointer will
remain valid until the thread has finished using it. In your
case, if `connfd' is a local variable in the "launcher"
function, it will cease to exist when that function returns.
If you passed `&connfd' to the newly-created thread, it will
find itself trying to use a pointer to a variable that has
been destroyed, and whose memory may have been overwritten by
other variables ...

More on this at comp.programming.threads.

</off-topic>
 
B

bwaichu

Richard said:
When you cast, you're saying to the compiler, "trust me, I know what I'm
doing, I won't hurt you, it'll be all right"; and the compiler looks
lovingly into your eyes, and *believes* you - even when it does actually
hurt quite a bit - and doesn't say a word.

Most of the time, alas, the compiler's trust is misplaced, because most of
the time the programmer is untrustworthy, and doesn't know what he's doing.
And it most certainly won't be all right.

Can I simply just apply a rule of thumb not to cast pointers to
non-pointers and vice versa? Or is there actually a right way to cast
pointers to non-pointers and vice versa?
 
R

Richard Heathfield

(e-mail address removed) said:

Can I simply just apply a rule of thumb not to cast pointers to
non-pointers and vice versa?

A (valid) pointer value is the address of an object or function. This might
be something like:

29059400
534277878593578937890000
DS:0A00
GRP9J14

It's easy to see how the first can be interpreted as an int. The second? A
bit harder, since we're running up against possible implementation limits.
The third? A bit trickier still - what would "DS:" /mean/ as an integer?
The fourth? Surely impossible.

A standard C program that /could/ cast meaningfully from a pointer to an
integer would, therefore, have to be capable of doing the impossible.
Or is there actually a right way to cast
pointers to non-pointers and vice versa?

If you have to do it, use a cast. For example:

unsigned long foo = (unsigned long)p; /* but does foo have enough bits? */

Better still: Just Don't Do That. Or at least, if you really really have to
do it, be aware that it has no portable semantics, and so you should
isolate it, along with your other non-portable code, into
easily-identifiable bits that you can rewrite for each targeted platform.
 
H

Herbert Rosenau

What is the best way to handle this warning:

warning: cast from pointer to integer of different size

Fix up the code. There is no need to cast pointer to int or int to
pointer. Even when in your environment they may have the same bitwidth
you may end up in undefined behavior.
I am casting in and out of a function that requires a pointer type. I
am casting an integer as a pointer, but the pointer is 8 bytes while
the integer is only 4 bytes.

When the fuction requires a pointer give it one. casting something to
a pointer is not a solution but a first range of source for undefined
behavior.
Here's an example function:

pthread_create(&tid, NULL, readit, (void *)(long)connfd)

I need to pass the file descriptor as a void * for pthread_create.

Untrue. You need to pass a pointer to a file descriptor.

But
I
need the file descriptor as an integer to read and write to it. Is the
above the best approach to turn off the warning? I am considering just
typecasting to size_t before typecasting to the pointer. Is that a
better
approach than typecasting to long since size_t should remain equal to
the size of pointers?

The best is to pass a pointer to the variable holding the value.
Of course, I run into the reverse problem when I have to close the
file descriptor.

close((int) arg);

Having the pointer to the descriptor here by hand you had anything you
needs.
I don't even know what to do in the above case. I shouldn't be
truncating
anything, so I should be okay.

I originally wrote the code using a 32 bit version, so I am receiving
these errors
when I ported it over to a 64 bit version.

Pass pointers when a pointer is required. Pass values when values are
required.

Hint: Since C89 you can always pass a pointer to data of any type when
a pointer to void is required. You can use the magic conversion to
compiler gives you to convert a pointer to void to the originam
pointer type without casting.

Attention: be sure that you never tries to pass a pointer to an auto
variable.

Hint: whenever you have to create a new thread and pass it its own
variables uses malloc to create a struct holding all variables you
have to pass and pass simply the pointer you got from malloc. Let the
thread free() that pointer when it has no need to use the data
therein. For that the last parameter of pthreads() is designed, not to
pass something that is not a pointer.

So it doesn't matter if your system is 16, 32, 48, 64 or 123 bits
wide.

Yeah, it will be a lot of work to rewrite the 32 bit app to get it -
but have it done it will work in 64 bit too without a change, making
maintenance a lot easier.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
S

Stephen Sprunk

Eric Sosman said:
<off-topic>

One cautionary note: Whenever you pass a pointer to an
asynchronously-executing thread -- at thread creation or at
any other time -- you must take care that the pointer will
remain valid until the thread has finished using it. In your
case, if `connfd' is a local variable in the "launcher"
function, it will cease to exist when that function returns.
If you passed `&connfd' to the newly-created thread, it will
find itself trying to use a pointer to a variable that has
been destroyed, and whose memory may have been overwritten by
other variables ...

More on this at comp.programming.threads.

</off-topic>

<OT>

When I do things like this, I malloc() an int and have the worker
thread free() it. That avoids doing things like:

int i = 1;
pthread_create(&tid, NULL, func, &i);
i = 2;
pthread_create(&tid, NULL, func, &i);
i = 3;
pthread_create(&tid, NULL, func, &i);

(Imagine that in a loop, where someone might not catch the
modification before use)

It also conveniently avoids the case where the int goes out of scope
(in the parent thread) before the worker thread is done with it.

</OT>

S
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top