Passing an integer to a function that accepts a void pointer

P

pozz

What do you think about this code?

int foo(const void *Args) {
printf("%d\n", (const int)Args);
return 0;
}

int main(int argc, char *argv[]) {
foo((void *)10);
return 0;
}

It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.

Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.
 
T

Tom St Denis

What do you think about this code?

int foo(const void *Args) {
  printf("%d\n", (const int)Args);
  return 0;

}

int main(int argc, char *argv[]) {
  foo((void *)10);
  return 0;

}

It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.

Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.

Why not just do this

int bar = 10;
foo(&bar);

And inside foo do

printf("%d\n", *((int *)Args));

That way the program is actually portable.

Tom
 
E

Eric Sosman

What do you think about this code?

Nothing good.
int foo(const void *Args) {
printf("%d\n", (const int)Args);
return 0;
}

int main(int argc, char *argv[]) {
foo((void *)10);
return 0;
}

It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.

It's not portable. Both the integer-to-pointer conversion in
the call and the pointer-to-integer conversion in the function are
implementation-defined, and the implementation is not required to
define them as inverses of each other. Many will so define them,
but it's not guaranteed. I've run into implementations that swizzle
the values on some integer/pointer/integer conversions, although to
be truthful I've only seen it with things like double* pointers, not
with void*.
Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.

Pthreads, perhaps? No matter: take Tom St Denis' advice and pass
a pointer to an int variable holding the desired value.
 
H

Heikki Kallasjoki

stdint.h defines a type name intptr_t which is an integer that can be converted
to a pointer and back again:
void *p = ...; intptr_t a = ...;

a is an integer variable and you can use << >> % etc with it.

(void*)(intptr_t)p == p
(intptr_t)(void*)a == a

The above is not entirely true. The intptr_t and uintptr_t types, if
they exist (they are optional), are capable of holding any valid
pointer-to-void value, but not the other way around. To quote the
C99 draft,

"The following type [intptr_t] designates a signed integer type with the
property that any valid pointer to void can be converted to this type,
then converted back to pointer to void, and the result will compare
equal to the original pointer"

In other words, the conversion to intptr_t and back is safe only for
valid pointers. Arbitrary integer values, even if they are stored in an
intptr_t object, are not guaranteed to be safely convertible to
pointers.
 
J

James Kuyper

What do you think about this code?

int foo(const void *Args) {
printf("%d\n", (const int)Args);
return 0;
}

int main(int argc, char *argv[]) {
foo((void *)10);
return 0;
}

It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.

It isn't portable. For the cast to void*: "... the result is
implementation-defined, ... and might be a trap representation."
(6.3.2.3p5). For the conversion back to int: "... the result is
implementation-defined. If the result cannot be represented in the
integer type, the behavior is undefined. The result need not be in the
range of values of any integer type." (6.3.2.3p6)

Note that the best you can hope for, as a result of either conversion,
is an implementation-defined result; there's nothing guaranteeing that
the implementation will define those results in such a way as to produce
a value of 10 (though it's not particularly unusual for them to do so -
that is why your defective code appears to be working).
Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.

Just create an object containing the value 10, and then pass a pointer
to that object. That's how the pointer parameter of the callback
function is intended to be used.
 
K

Keith Thompson

Columbus sailed the ocean China Blue said:
The above is not entirely true. The intptr_t and uintptr_t types, if
they exist (they are optional), are capable of holding any valid
pointer-to-void value, but not the other way around. To quote the
C99 draft,

"The following type [intptr_t] designates a signed integer type with the
property that any valid pointer to void can be converted to this type,
then converted back to pointer to void, and the result will compare
equal to the original pointer"

In other words, the conversion to intptr_t and back is safe only for
valid pointers. Arbitrary integer values, even if they are stored in an
intptr_t object, are not guaranteed to be safely convertible to
pointers.

That's nice. Any compiler that screws this up will break so much
software that it will be rejected.

I'm sure there's plenty of software that assumes it can safely
convert integers to pointers. Much of it probably does so
unnecessarily, and much of it makes non-portable assumptions about
the relative sizes of integer and pointer types, and is likely to
break on 64-bit systems. I suspect that most programmers who are
aware of the existence of intptr_t and uintptr_t are experienced
enough to know that they're rarely the right solution.

But how much software depends on being able to convert arbitrary
integer values to pointers? Why would you even want to do that?
 
K

Keith Thompson

Columbus sailed the ocean China Blue said:
Most callback interfaces designed in the last dozens of years depend on that.

Can you provide a concrete example?
 
K

Kenny McCormack

Can you provide a concrete example?

Yes. He can.

http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/questions-with-yes-or-no-answers.html

--
But the Bush apologists hope that you won't remember all that. And they
also have a theory, which I've been hearing more and more - namely,
that President Obama, though not yet in office or even elected, caused the
2008 slump. You see, people were worried in advance about his future
policies, and that's what caused the economy to tank. Seriously.

(Paul Krugman - Addicted to Bush)
 
F

Fred

What do you think about this code?
int foo(const void *Args) {
 printf("%d\n", (const int)Args);
 return 0;
}
int main(int argc, char *argv[]) {
 foo((void *)10);
 return 0;
}
It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.
Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.

I must be missing something.

What library callback are you referring to?

One example might be the XtCallback on Unix:

void CallbackProc( Widget w, XtPointer clientData, XtPointer
callData )

where XtPointer is defined as a "void *".

The app registers the callback using:
XtAddCallback( myWidget, XtXxxxCallback, CallbackProc, clientData );

where clientData was often some integer flag. Passing a pointer to
an integer would require that integer to remain in scope globally,
since the registration code and the callback code might be in
different compilation units.

Many of the examples in the Flannagan's O'Reilly series of
manuals do this sort of thing.

This type of coding, of course, should not be recommended, and
can cause a lot of headaches when porting to a 64-bit platform
where int and pointer are different sizes.
 
D

Dr Nick

Datesfat Chicks said:
What do you think about this code?

int foo(const void *Args) {
printf("%d\n", (const int)Args);
return 0;
}

int main(int argc, char *argv[]) {
foo((void *)10);
return 0;
}

It seems work and it should be nice if it is a sufficient portable way
to pass integers as pointers.

Why don't I declare foo() to directly accept int? Because it is a
callback of a library I can't change and the prototype of the callback
is well defined by the library to accept void pointer.

I must be missing something.

What library callback are you referring to?

An example might be the one I was criticising qsort for not providing in
another thread.

It's generally useful to make any function that uses a callback take a
void * parameter that it passes untouched to the callback. This can
contain any information the callback needs, or can even collect
information from the callback.

If you do need to pass an integer, you need some way to put it into a
void *. This is one way - that I wouldn't use: I'd use an int variable
and take its address as previously suggested.
 
S

Seebs

Most callback interfaces designed in the last dozens of years depend on that.

I've never seen that be a requirement of the interface. If you want to
pass an integer in, you pass its address. Otherwise you are exposing
yourself to Unknown Bad Shit.

I never saw any need to take the extra risk.

-s
 
S

Shao Miller

Il 11/05/2011 12:52, Tom St Denis ha scritto:

Oh yes, this is another solution I considered and surely it is the most
portable way.

In my case, I have a long list of const struct initialized with callback
and argument pointers, like this:
...

In your example code, you are using the same call-back for every
different number. If you are going to be using the same call-back, is
there a reason why you cannot pass a 'void *' context that points
directly to an element of an array of 'int'? As in:
---
#include <stdlib.h>
#include <stdio.h>

/*** Constants */
/* None */

/*** Object type declarations */
typedef unsigned char byte;

/*** Function types */
typedef int f_callback(const void *);
typedef int f_intfunc(int);

/*** Structure type definitions */
/* None */

/*** Function declarations */
static f_callback my_callback;
static f_intfunc some_func;

/* This one doesn't belong to you and comes from a header */
extern int SomeApiPerformCallback(f_callback *, const void *);

/*** Objects */
static int my_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

/*** Function definitions */

/**
* This callback will call 'some_func' with the 'int' value
* context that is associated with it.
*/
static int my_callback(const void * context) {
const int * int_ptr;

int_ptr = context;
if (!int_ptr)
return -1;

printf("my_callback() context: %p\n", context);
return some_func(*int_ptr);
}

/**
* This quite simply returns the 'int' that is passed
*/
static int some_func(int int_param) {
printf("some_func() got: %d\n", int_param);
return int_param;
}

/**
* The program entry-point
*/
int main(void) {
int result;

result = SomeApiPerformCallback(my_callback, my_ints + 5);
if (result == -1)
return EXIT_FAILURE;
printf("Result: %d\n", result);

result = SomeApiPerformCallback(my_callback, my_ints + 7);
if (result == -1)
return EXIT_FAILURE;
printf("Result: %d\n", result);

result = SomeApiPerformCallback(my_callback, my_ints + 3);
if (result == -1)
return EXIT_FAILURE;
printf("Result: %d\n", result);

return EXIT_SUCCESS;
}

/* This one doesn't belong to you and is just a demo */
int SomeApiPerformCallback(f_callback * callback, const void * context) {
if (!callback)
return -1;

return callback(context);
}

---

I would expect that unlike this simple code, you are registering a
call-back which will be executed asynchronously relative to the function
which registers it. In that case, unless you wish to wait for the
call-back to complete, I can understand why you wouldn't want to do:

void blah(void) {
int i;

/* ... */
i = 5;
SomeApiRegisterCallback(my_callback, &i);
return;
}

because the lifetime of 'i' will end pretty well immediately after
you've registered your call-back. :) But... That's what malloc() and
the other memory allocation functions are for...

void blah(void) {
int *i;

i = malloc(sizeof *i);
if (!i) {
/* Note an error */
return;
}

*i = 5;
SomeApiRegisterCallback(my_callback, i);
return;
}

Remember to free() the pointer once you've finished with it. :)

Any pointer type which points to a complete or incomplete object type
can be converted to 'void *' (and back again), if I recall correctly.
So that includes 'int *' -->> 'void *'.
 
I

Ian Collins

Then you haven't seen any libraries that pass through a callerData to a callback
function. These libraries advertise that can be a data pointer or small enough
integer. Or unix signal interface. Or Tcl file handle interface.

Well I've seen plenty and none of them made that claim. They either
take an integer (signal callbacks) or a (typically void*) pointer.
Anything else is a hack.
 
H

Heikki Kallasjoki

Well I've seen plenty and none of them made that claim. They either
take an integer (signal callbacks) or a (typically void*) pointer.
Anything else is a hack.

The POSIX signal interface accepts the user-provided "signal value"
(when sending signals with sigqueue(2)) as an integer-pointer union,

union sigval {
int sival_int;
void *sival_ptr;
};

Sending such union values around is of course a safe way to pass either
a pointer or an integer. (Assuming the handler knows which type of
value to expect.)
 
E

Eric Sosman

[...]
In other words, the conversion to intptr_t and back is safe only for
valid pointers. Arbitrary integer values, even if they are stored in an
intptr_t object, are not guaranteed to be safely convertible to
pointers.

That's nice. Any compiler that screws this up will break so much software that
it will be rejected.

This is how bad code hurts better code. Suppose you're a compiler
writer, and you've figured out a nifty little optimization that reduces
the time for pointer operations by X% but makes pointer/integer
conversion pretty much meaningless. Do you implement the optimization
and let the existing bad code fail, or do you suppress it to keep the
bad code running -- and run good code X% slower?

Oh, yes, it happens. The X's may be small, but they are numerous.
Remember, this is a newsgroup where people will fret endlessly about
whether `++i' or `i++' is faster ...
 
E

Eric Sosman

Eric Sosman said:
[...]
In other words, the conversion to intptr_t and back is safe only for
valid pointers. Arbitrary integer values, even if they are stored in an
intptr_t object, are not guaranteed to be safely convertible to
pointers.

That's nice. Any compiler that screws this up will break so much software
that
it will be rejected.

This is how bad code hurts better code. Suppose you're a compiler
writer, and you've figured out a nifty little optimization that reduces
the time for pointer operations by X% but makes pointer/integer

Because this is irrelevant. Interfaces that allow integers to be passed through
as (void*) also promise they make no changes to the void pointers, that they are
passed through unchanged.

Interfaces that make such promises are making promises that go
beyond the C language itself. This is perfectly legitimate, just like
interfaces that promise meaningful conversion between void* and function
pointers or interfaces that promise a 64-bit `long' or interfaces that
promise the existence of an third argument to main(). These promises
are valid IN THE DOMAIN OF THE PROMISOR, but are not binding on other
C implementations.

Besides, you're begging the question, which boils down to "Can an
int be converted to void* and back without change?" When you begin
your answer with "Interfaces that allow integers to be passed through
as (void*) ..." you have evaded the entire issue.
It's becoming clear that a large group of 'C experts' have no experience how C
is actually used. Feel free to whinge about this amongst yourself, but be aware
you will have no effect on the rest of the world.

Can't speak for others, but my own ~3.5 decades of C experience
haven't enabled me to make much impact on the intentionally stupid.
 
K

Keith Thompson

Columbus sailed the ocean China Blue said:
[...]
In other words, the conversion to intptr_t and back is safe only for
valid pointers. Arbitrary integer values, even if they are stored in an
intptr_t object, are not guaranteed to be safely convertible to
pointers.

That's nice. Any compiler that screws this up will break so much software
that
it will be rejected.

This is how bad code hurts better code. Suppose you're a compiler
writer, and you've figured out a nifty little optimization that reduces
the time for pointer operations by X% but makes pointer/integer

Because this is irrelevant. Interfaces that allow integers to be
passed through as (void*) also promise they make no changes to
the void pointers, that they are passed through unchanged.

Do you have a concrete example of an interface that expects a void*
argument, and depends on the ability to convert an arbitrary integer
value to a pointer without loss of information?
It's becoming clear that a large group of 'C experts' have no
experience how C is actually used. Feel free to whinge about
this amongst yourself, but be aware you will have no effect on
the rest of the world.

This would be a lot clearer if you'd back up your specific claims.
 
K

Kenny McCormack

Keith "Kiki" Thompson said:
Do you have a concrete example of an interface that expects a void*
argument, and depends on the ability to convert an arbitrary integer
value to a pointer without loss of information?

Yes, he does.

http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/questions-with-yes-or-n
o-answers.html

Yes, that's the beauty of clc. Welcome & enjoy!
This would be a lot clearer if you'd back up your specific claims.

The insanity of this latest from the Kikster absolutely boggles the mind.

--
(This discussion group is about C, ...)

Wrong. It is only OCCASIONALLY a discussion group
about C; mostly, like most "discussion" groups, it is
off-topic Rorsharch [sic] revelations of the childhood
traumas of the participants...
 
S

Seebs

Because this is irrelevant.

I don't think you are really understanding the claim...
It's becoming clear that a large group of 'C experts' have no
experience how C is actually used. Feel free to whinge about this
amongst yourself, but be aware you will have no effect on the rest
of the world.

I suspect we have rather a bit more experience how C is actually used than
you think, largely because, well... I know what some of these people do.

I have never, ever, seen an interface which takes a (void *) argument as
a callback parameter claim that anything other than (void *) is meaningful
or acceptable to it. I have also never seen anyone write code which uses
such an interface and doesn't pass it pointers. And if such code came near
me for code review, it would get NAKd, because my job is to make sure that
code will run reliably across about sixty processors and also on new
processors we haven't seen yet. That, it turns out, means not playing silly
buggers for no reason.

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

Latest Threads

Top