Passing an integer to a function that accepts a void pointer

S

Shao Miller

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?

In Windows driver-land, there is an 'IO_STATUS_BLOCK'[1] structure type
which has a 'ULONG_PTR' member called 'Information'. Sometimes this is
populated with an integer value. Sometimes this is populated by casting
a pointer to 'ULONG_PTR'.

My understanding is that this is not portable in a standard sense, but I
just thought I'd offer it as a potentially related example. In this
case, it's the other way 'round than converting an integer to 'void *'.

[1] http://msdn.microsoft.com/en-us/library/ff550671(VS.85).aspx
 
S

Shao Miller

Il 12/05/2011 05:10, Shao Miller ha scritto:

Oh yes, it is exactly what I wrote in the previous post. The approach is
good, but two small drawbacks I posted.

So if you are using the same call-back function no matter which element
is being used, would it make sense to remove the redundant '.fn' member
and simply pass a context which points directly to an element of an
array of 'int'?
malloc() and free() are not present in my embedded system. I have to use
only static allocation.

That detail seems like a good idea to share when discussing your
scenario. :)

Can your function which registers the call-back wait for the call-back
to be completed?

If not, is the call-back one which will be called repeatedly, but should
always use the same context?

Do you have thread synchronization functions available to you?

Could you have a dedicated thread whose sole purpose is to provide for
non-static storage? Such a thread could "abuse" recursion in order to
"allocate" more memory in the form of automatic objects. The memory
could run out, obviously, but could save you from having a large array
with static duration and having every possible number in it. Or is
having such a large array not an issue?

Or could you have a thread to "wrap" each context? A thread for "3", a
thread for "5", etc.? That'd seem _quite_ wasteful, but maybe that's an
option!

In my opinion, if you are targeting a particular environment (which
doesn't have malloc() and free() ), then perhaps you needn't be overly
concerned about portability! If the environment is documented as
allowing for an 'int' to be cast to 'void *' and back again, then that's
that. (But maybe avoid expecting such code to be portable, in a
standard sense.)

Have a pleasant day. :)
 
K

Keith Thompson

Shao Miller 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?

In Windows driver-land, there is an 'IO_STATUS_BLOCK'[1] structure type
which has a 'ULONG_PTR' member called 'Information'. Sometimes this is
populated with an integer value. Sometimes this is populated by casting
a pointer to 'ULONG_PTR'.

My understanding is that this is not portable in a standard sense, but I
just thought I'd offer it as a potentially related example. In this
case, it's the other way 'round than converting an integer to 'void *'.

[1] http://msdn.microsoft.com/en-us/library/ff550671(VS.85).aspx

ULONG_PTR is an unsigned integer type (I had assumed from the name that
it was a pointer type). According to
<http://msdn.microsoft.com/en-us/library/cc230394(v=prot.10).aspx>:

A ULONG_PTR is an unsigned long type used for pointer
precision. It is used when casting a pointer to a long type to
perform pointer arithmetic.

This type is declared as follows:

typedef unsigned __int3264 ULONG_PTR;

where __int3264 is either 32 or 64 bits. So it seems to play a similar
role to standard C's uintptr_t.

(Of course, you don't need to cast a pointer to a long type to perform
pointer arithmetic; pointer arithmetic works on pointers.)

And as you say, it's not an example of what I was asking "Columbus
sailed the ocean China Blue" about.
 
S

Shao Miller

Il 12/05/2011 20:16, Shao Miller ha scritto:

In the array of struct, many callback are the same, but other aren't.
They aren't ALL the same.

Ok, I misunderstood your post before. Sorry about that. :)
No, the callback will be asincronously called automatically by the
library (when deterministic events occurs).

I had to ask. Heheh.
I have many callback functions I'd like to register. Some of them can be
called with different contexts.

I had to ask that, too. Heheh.

Well that's too bad. Do you at least have a function which will cause a
thread to sleep and provide an opportunity for another thread (such as
one that invokes your call-back) to execute?

Or is this the type of scenario where you are expected to register
call-backs and then yield control back to a higher-level function that
is not your own, effectively ending your program until a call-back is
invoked?
What is the reason I couldn't expect a piece of code without malloc/free
to be portable?

That's not what I meant. I meant, as has been expressed by other
respondents in your thread here, that casting an 'int' to a 'void *' is
not portable in a standard sense, according to the n1256.pdf draft's
section 6.3.2.3, point 5. An implementation might define it as
unsupported, if I'm not mistaken.
 
M

Michael Press

Paul N said:
Pah! That's only one step from actually asking the intended question.

Consider the following, actually said by my mother:

"I don't know whether you want to help your father."

How many steps does it take to get from that to the actual meaning?

People seeking help can be helped by coaxing them
into asking precise questions. Often a problem
solves itself once the question is made sharp enough,
eliminating the need even to ask the question in a forum.
Do not underrate the benefit to the forum at large.
Helping people who ask imprecise or vague questions
is wearing. Answering well posed questions can be
interesting in itself---the opposite of wearing.
 
K

Keith Thompson

Michael Press said:
[...]
Can you provide a concrete example?
[snip]

Pah! That's only one step from actually asking the intended question.

Consider the following, actually said by my mother:

"I don't know whether you want to help your father."

How many steps does it take to get from that to the actual meaning?

People seeking help can be helped by coaxing them
into asking precise questions. Often a problem
solves itself once the question is made sharp enough,
eliminating the need even to ask the question in a forum.
Do not underrate the benefit to the forum at large.
Helping people who ask imprecise or vague questions
is wearing. Answering well posed questions can be
interesting in itself---the opposite of wearing.

I'm all for precise questions, but the implicit meaning of "Can
you provide a concrete example" is clear enough to anyone who's not
deliberately trying to be difficult (as one poster in this thread,
not quoted here, clearly is).

And if the person of whom I actually asked the question, someone
posting as "Columbus sailed the ocean China Blue", wanted to take
it literally and just say "Yes", there would at least be a basis
for further discussion.

My current working hypothesis, given the lack of an actual
response, is that there are no such concrete examples, or at least
no significant ones, and that a C compiler that didn't support
converting arbitrary integer values to pointers without loss of
information wouldn't break much existing code.

There are plenty of things whose behavior is undefined, but that
C compilers can't afford to break, but I'm not convinced that this
is one of them.
 
M

Michael Press

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
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?

That works both ways. A language lumbered with dozens of
little inconveniences will be abandoned. When compiler
writers start to think the C programming language is
their own little sandbox, the language is in trouble.
Optimization always has its cost to weigh against its benefit;
and one of the costs is losing people who use the language.
 
S

Seebs

If you're finished digging yourself into a hole, you can start with
man brk

Steeeeerike one!

brk()'s argument is a "void *" and is not an int, nor is it meaningful or
valid to pass an int to it. The one which takes integer arguments is
sbrk().

Care to try again?

-s
 
I

Ian Collins

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.)

Exactly the point, it uses a union to make the process safe.
 
I

Ian Collins

Steeeeerike one!

brk()'s argument is a "void *" and is not an int, nor is it meaningful or
valid to pass an int to it. The one which takes integer arguments is
sbrk().

Bugger, you beat me to it!
 
S

Shao Miller

Bugger, you beat me to it!

Question: If the argument to brk() is an address which will be one-past
the new highest address, how do you build that pointer?
 
K

Keith Thompson

Columbus sailed the ocean China Blue said:
If you're finished digging yourself into a hole, you can start with
man brk

Otherwise feel free to dazzle your admirers with your inexperience.

Ok, I just checked the brk man page. On my system, it's declared as

int brk(void *addr);

There is no suggestion in the man page that the argument should be
anything other than an address; in particular, there's no hint that
passing some arbitrary integer value, converted to void*, would be
meaningful.

There's probably no way to construct a meaningful argument value while
staying within the bounds of behavior defined by the C standard, but
that's to be expected for such a low-level function.

I don't believe brk() is an example of what we were discussing.

For your reference, here's the question I asked you before:

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?

If you don't have such an example, "no" is a perfectly acceptable answer.
 
I

Ian Collins

Question: If the argument to brk() is an address which will be one-past
the new highest address, how do you build that pointer?

One past the new data segment, not the new highest address.
 
K

Keith Thompson

Shao Miller said:
Question: If the argument to brk() is an address which will be
one-past the new highest address, how do you build that pointer?

In some blatantly non-portable manner.

There's probably some way to get the current "break" value as
a void*. Given that value, you can add to it (by any of several
methods) and pass the result to brk(). Or you can use sbrk(), which
takes care of most of the bookkeeping for you. (Or, as the man
page recommends rather strongly, use malloc() to allocate memory.)
 
S

Seebs

One past the new data segment, not the new highest address.

In any event, it's easy enough. Given a current address, "void *a", you
do:
char *b = a;
b += 20000;
a = b;

you can do pointer arithmetic on a char *, and use this to generate new
pointers. At no point does this process rely on the ability to pass
integers to functions which expect pointers.

-s
 
K

Keith Thompson

Seebs said:
In any event, it's easy enough. Given a current address, "void *a", you
do:
char *b = a;
b += 20000;
a = b;

you can do pointer arithmetic on a char *, and use this to generate new
pointers. At no point does this process rely on the ability to pass
integers to functions which expect pointers.

Right. Though it does make some non-portable assumptions about
address arithmetic -- assumptions that are almost certain to be
valid on any system on which brk() makes any sense.

(Note that gcc permits arithmetic on void* as if it were char*.
Code that calls brk() is likely to be so non-portable that depending
on a gcc extension may not be a problem.)
 
S

Shao Miller

Right. Though it does make some non-portable assumptions about
address arithmetic -- assumptions that are almost certain to be
valid on any system on which brk() makes any sense.

Perhaps you are thinking of pointer arithmetic only being defined, in a
standard sense, when pointing within the same array object[6.5.6p8]?
(Note that gcc permits arithmetic on void* as if it were char*.
Code that calls brk() is likely to be so non-portable that depending
on a gcc extension may not be a problem.)

Agreed.

So a follow-up question:

- Does anyone ever use brk() to specify an absolute address, or only to
shrink/grow by some amount?
 
K

Keith Thompson

Shao Miller said:
Right. Though it does make some non-portable assumptions about
address arithmetic -- assumptions that are almost certain to be
valid on any system on which brk() makes any sense.

Perhaps you are thinking of pointer arithmetic only being defined, in a
standard sense, when pointing within the same array object[6.5.6p8]?

Exactly.

[...]
 
E

Eric Sosman

[...]
malloc() and free() are not present in my embedded system. I have to use
only static allocation.

malloc() is absent but printf() is present? It's possible,
certainly, but seems unlikely if not downright perverse.

Anyhow, implementing a quick-and-dirty malloc() work-alike
based on a static array shouldn't take anyone more than an hour.
 
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
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?

That works both ways. A language lumbered with dozens of
little inconveniences will be abandoned. When compiler
writers start to think the C programming language is
their own little sandbox, the language is in trouble.
Optimization always has its cost to weigh against its benefit;
and one of the costs is losing people who use the language.

That's what makes the Standard-as-contract valuable: It describes
the freedoms of both the user-programmer and the implementor. Have
you heard the maxim "Code to the interface, not the implementation?"
The Standard's job is to codify the interface; everybody benefits when
user-programmer and implementor stay on their own sides of the border.

As for "will be abandoned," I'm not at all sure you're right.
C *is* loaded with dozens of little inconveniences, yet it is (my
guess) the third longest-surviving language in general use today,
behind Fortran and COBOL, languages if anything even more loaded
with inconveniences than C. Language longevity seems not so strongly
influenced by aesthetics as you appear to suppose.
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top