CAN WE TYPE CAST AN INTEGER AS (VOID *)X..(Like can I return a value (void *)x)

A

Abhishek

now suppose I have declared an integer value inside a function as
int x;
now if the return type of the function is of type (void *) then can I
write
return((void *)x) in side the function?
I came across this in a document on multithreading in C..I can post the
exact portion of code which works correctly with such an assignment if
you people want.
Please clarify my doubt.I hope I have conveyed it properly.
 
I

Ico

Hello Abhishek,

Please do not write sentences in ALL UPPERCASE. This will only cause
people to ignore your posts, since this is a style which is often used
by spammers. Also, try to keep your subject short, since some people
might be using newsreaders which are not able to display too long
subject lines. A good subject for your post might have been something
like "Casting int to void *"

Abhishek said:
now suppose I have declared an integer value inside a function as int
x; now if the return type of the function is of type (void *) then can
I write return((void *)x) in side the function?

Yes, this is possible, but I suspect this might result in undefined
behaviour. By casting an int to a void pointer, you take the number in
x, and convert it to an address. You are telling your compiler `trust
me, I know what I am doing. Although this is just a regular number, I am
sure this number is a valid address of something which doesn't have a
specific type'. This might or might not work on your platform, since
there is no guarantee that an int might fit into a pointer. I am not
aware of any good reasons for using an integer type to store a pointer,
although I am aware of other code where this is common practice (the
Linux kernel). Maybe somebody else can explain why this is done.

Ico
 
V

Vladimir S. Oka

Ico said:
Hello Abhishek,

Please do not write sentences in ALL UPPERCASE. This will only cause
people to ignore your posts, since this is a style which is often used
by spammers.

I must say, my immediate reaction to ALL CAPS tends to be STOP
SHOUTING! ;-)

Yes, this is possible, but I suspect this might result in undefined
behaviour. By casting an int to a void pointer, you take the number in
x, and convert it to an address. You are telling your compiler `trust
me, I know what I am doing. Although this is just a regular number, I
am sure this number is a valid address of something which doesn't have
a specific type'. This might or might not work on your platform, since
there is no guarantee that an int might fit into a pointer. I am not
aware of any good reasons for using an integer type to store a
pointer, although I am aware of other code where this is common
practice (the Linux kernel). Maybe somebody else can explain why this
is done.

This is certainly undefined behaviour, if not worse. Once you return
from the function, as far a C Standard is concerned, all objects local
to that function _cease_to_exist_ (as was mentioned elsewhere in c.l.c,
Standard knows nothing about stacks and similar real world concepts).
Referring to them outside the function should really make your head
spin. ;-)

Of course, an implementation is allowed to take shortcuts by not
bothering to physically destroy such objects, and so you may not get
illegal access or whatever error is appropriate. However, even changing
optimisation level, let alone the whole compiler may make your (OP's)
code behave in a totally different way.

Cheers

Vladimir

Cheers

Vladimir
 
I

Ico

Vladimir S. Oka said:
This is certainly undefined behaviour, if not worse. Once you return
from the function, as far a C Standard is concerned, all objects local
to that function _cease_to_exist_ (as was mentioned elsewhere in c.l.c,
Standard knows nothing about stacks and similar real world concepts).
Referring to them outside the function should really make your head
spin. ;-)

Of course, an implementation is allowed to take shortcuts by not
bothering to physically destroy such objects, and so you may not get
illegal access or whatever error is appropriate. However, even changing
optimisation level, let alone the whole compiler may make your (OP's)
code behave in a totally different way.

Vladimir, I think you misread the details in the OP's question: as far
as I onderstood, he is not returning the address of x, but the *value*
of x, casted to void * :

Apart from the cast, this is just as valid as returning x intself.

Ico
 
E

Eric Sosman

Vladimir said:
Ico wrote:




I must say, my immediate reaction to ALL CAPS tends to be STOP
SHOUTING! ;-)




This is certainly undefined behaviour, if not worse. Once you return
from the function, as far a C Standard is concerned, all objects local
to that function _cease_to_exist_ (as was mentioned elsewhere in c.l.c,
Standard knows nothing about stacks and similar real world concepts).
Referring to them outside the function should really make your head
spin. ;-)

This is true, but has nothing to do with the question.

The O.P. has run across a function whose return type is
`void*' <ot> because of the requirements of a framework that
is not topical here </ot>. However, in the context of the
actual function it makes more sense to return an `int'. The
code tries to do so by converting the `int' to a `void*';
presumably, the caller retrieves the `void*' and converts it
back to an `int' again. The O.P. asks whether C guarantees
that this will work as desired.

The answer (may I have the envelope, please?) is "No."
An integer can be converted to any pointer type (6.3.2.3/5),
but the result is implementation-defined. A pointer can be
converted to an integer (6.3.2.3/6), but again the result is
implementation-defined. It is not guaranteed that the two
conversions are inverses; that is, it is not guaranteed that
the number that emerges from the second conversion is the same
value that entered the first. In fact, either or both of the
conversions may yield trap values, and the mere act of trying
to do something with a trap value (e.g., return it from a
function) yields undefined behavior.

That said, the dubious practice will in fact work as desired
on many implementations (I suspect it might fail on AS/400, but
I'm not sure of that). Completely portable approaches exist,
but some programmers are too lazy or too unimaginative to use
them. The O.P. is looking at such a programmer's product.
 
R

Robin Haigh

Abhishek said:
now suppose I have declared an integer value inside a function as
int x;
now if the return type of the function is of type (void *)
then can I write
return((void *)x) in side the function?
I came across this in a document on multithreading in C.


6.3.2.3 p5 says an integer may be converted to a pointer type. The result
is implementation-defined.

This doesn't mean undefined behaviour: it means the implementation is
required to make it work and tell you how.

The document where you saw this is discussing the multithreading extension
in a particular implementation. The code relies on other features of the
implementation, but that doesn't make it any more non-portable than it
already is.

I suspect there's no intention of using the return value as a pointer. It
probably does something like

retp = func();
if (retp == (void *)-1) {
/* handle special case */
} else {
/* retp is a normal pointer */
}

This isn't as elegant as some people might like, but it's fine
 
K

Keith Thompson

Robin Haigh said:
6.3.2.3 p5 says an integer may be converted to a pointer type. The result
is implementation-defined.

This doesn't mean undefined behaviour: it means the implementation is
required to make it work and tell you how.

Right, but here's the whole of 6.3.2.3p5:

An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might
not be correctly aligned, might not point to an entity of the
referenced type, and might be a trap representation.

and a footnote:

The mapping functions for converting a pointer to an integer or an
integer to a pointer are intended to be consistent with the
addressing structure of the execution environment.
The document where you saw this is discussing the multithreading extension
in a particular implementation. The code relies on other features of the
implementation, but that doesn't make it any more non-portable than it
already is.

I suspect there's no intention of using the return value as a pointer. It
probably does something like

retp = func();
if (retp == (void *)-1) {
/* handle special case */
} else {
/* retp is a normal pointer */
}

This isn't as elegant as some people might like, but it's fine

If retp happens to be a trap representation, evaluating it for the
purpose of comparing it to (void*)-1 invokes undefined behavior. For
that matter, assigning the result of func() to retp in the first place
probably invokes undefined behavior.

The code is portable only to systems on which the conversion doesn't
yield a trap representation (which may well be all the systems on
which the code is expected to run).

<OFF_TOPIC>
I think POSIX has at least one function that uses -1 converted to a
pointer type as a special return value.
</OFF_TOPIC>

Let's look at the original problem. You have a function that normally
returns a pointer value (void*), but sometimes you want an integer
value. There are at least two cases to consider.

If you want a single, or a small number of, distinctive values other
than NULL, using (void*)-1 can work on many platforms, but strictly
speaking it's non-portable (and frankly it's ugly).

A portable solution is to declare an otherwise-unused object and use
its address as a special value.

If you just want to return either a pointer or a arbitrary integer
value, then you probably have a poorly designed interface. The
function can return a record (or a union) containing both a pointer
and an integer, and some indication of which is valid. Or it can
return extra information indirectly via a parameter. And so forth.

Or if the caller can know in advance whether the result is going to be
a pointer or an integer, perhaps there should be two separate
functions.
 
R

Robin Haigh

Keith Thompson said:
Right, but here's the whole of 6.3.2.3p5:

An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might
not be correctly aligned, might not point to an entity of the
referenced type, and might be a trap representation.


If you're quoting C89, you've got me, I was using the C99 draft (N869).
This doesn't have the last bit ("and might be a trap representation").

That's because it's meaningless. 6.3.2.3 comes under "Conversions". A
conversion takes a value and yields a value. A value is just an
intermediate in expression evaluation, and we know nothing about how it may
be held, or represented in whatever it's held in. (I say "held" because it
isn't "stored" until it's assigned to a storage object)

A trap representation is an object representation that doesn't have a value.
An object representation is created when a value is written into a
byte-addressed storage object (e.g. a variable), by encoding the value into
an ordered sequence of bytes (which are now visible, by way of a pointer
cast). (6.2.6)

That's still working from C99. The wording you quote from C89 seems to be
based on a different concept of trap representation?
 
K

Keith Thompson

Robin Haigh said:
If you're quoting C89, you've got me, I was using the C99 draft (N869).
This doesn't have the last bit ("and might be a trap representation").

No, I was quoting N1124, which includes C99 plus TC2. I just checked
and the actual C99 standard has the same wording (and there are no
change bars in that section in N1124). Apparently the trap
representation wording was added between N860 and the actual standard.
That's because it's meaningless. 6.3.2.3 comes under "Conversions". A
conversion takes a value and yields a value. A value is just an
intermediate in expression evaluation, and we know nothing about how it may
be held, or represented in whatever it's held in. (I say "held" because it
isn't "stored" until it's assigned to a storage object)

A trap representation is an object representation that doesn't have a value.
An object representation is created when a value is written into a
byte-addressed storage object (e.g. a variable), by encoding the value into
an ordered sequence of bytes (which are now visible, by way of a pointer
cast). (6.2.6)

That's a good point. I think the wording I quoted is *trying* to say
something important, but it blurs the distinction between values and
representations (not the only place the standard does this).

Given:

int i = some_value;
void *p = (void*)i;

it seems obvious (to me) that p might have a trap representation after
it's initialized. The alternative would be either to require void*
not to have any trap representations, or to require implementations to
go to heroic efforts to avoid letting conversions generate trap
representations.

The standard tries to cover this by saying that the value yielded by
the conversion "might be a trap representation". I see the problem,
but I don't know how to fix it. The simplest fix would be just to say
that trap representations are values.
 
V

Vladimir S. Oka

Vladimir, I think you misread the details in the OP's question: as far
as I onderstood, he is not returning the address of x, but the *value*
of x, casted to void * :


Apart from the cast, this is just as valid as returning x intself.

Ah, you're absolutely right (and so is Eric). I stand corrected.

I think I jumped ahead of myself (and OP), thinking of what one would
_do_ with such a value returned from the function. Trying to
dereference it would most likely be a bad idea (unless maybe one is
implementing a *alloc() replacement).

Cheers

Vladimir
 
V

Vladimir S. Oka

Ico said:
Vladimir, I think you misread the details in the OP's question: as far
as I onderstood, he is not returning the address of x, but the *value*
of x, casted to void * :


Apart from the cast, this is just as valid as returning x intself.

Ico

Vladimir, you muppet! You are henceforth barred from posting before 9 AM
and/or before having at least three (3) mugs of strong coffee!

The above applies to my previous reply, especially (which I still can't
see, and think will have to do un/re-subscribe to c.l.c dance again)!

Clerk, please strike Vladimir's statements in this case.

I'm kneeling on some corns for a while... :-(

Cheers

Vladimir
 
O

Old Wolf

Eric said:
The O.P. has run across a function whose return type is
`void*' <ot> because of the requirements of a framework that
is not topical here </ot>. However, in the context of the
actual function it makes more sense to return an `int'. The
code tries to do so by converting the `int' to a `void*';
presumably, the caller retrieves the `void*' and converts it
back to an `int' again. The O.P. asks whether C guarantees
that this will work as desired.

The answer (may I have the envelope, please?) is "No."

That said, the dubious practice will in fact work as desired
on many implementations (I suspect it might fail on AS/400, but
I'm not sure of that). Completely portable approaches exist,
but some programmers are too lazy or too unimaginative to use
them. The O.P. is looking at such a programmer's product.

A portable solution within this framework is to make x static
and return its address. Then convert back to (int *) in the
calling function.
 
E

Eric Sosman

Old Wolf wrote On 01/30/06 08:28,:
A portable solution within this framework is to make x static
and return its address. Then convert back to (int *) in the
calling function.

Yes, <ot> but that's not a good idea in multi-
threaded code, which is what the O.P. is studying.
As it happens, the POSIX multi-threading framework
dictates that the signature of the function must be

void* function(void*)

.... and it's easy to use the argument as a pointer
to a place where the "returned" value -- int, double,
or whatever -- can be deposited. </ot>

Another safe way to disguise a smallish integer
as a pointer is to point at something:

char fake[10];
...
void* function(void* arg) {
int x;
...
return &fake[x]; /* 0 <= x <= 10 */
}
...
/* caller: */
int x = (char*)result_of_f - fake;
 

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,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top