ra*******@gmail.com wrote:
hello,
In kernel source code there is ip_fragment.c file my question is
regarding pointer function and casting for that look at required
snippet from that file
[... snipped even further; see up-thread ...]
static void ip_expire(unsigned long arg)
{
struct ipq *qp = (struct ipq *) arg;
[... in function ip_frag_create() ...]
/* Initialize a timer for this entry. */
init_timer(&qp->timer);
qp->timer.data = (unsigned long) qp; /* pointer to queue */
qp->timer.function = ip_expire; /* expire function */
[...]
My question is
1)how ip_expire is called in ip_frag_create? I mean where is its
argument. check that function above.
This is not a function call at all. It is an assignment:
`X = Y'. The `X' is a field in a struct or union (we can
deduce that much from the `.' syntax), probably a struct.
You didn't show the declaration of this struct or union type,
but we can also infer that its `function' field is a pointer.
Not a pointer to a data object, but a pointer to a function --
and the `Y' piece is the "target" of this pointer, the function
that the pointer points to.
At some later time, some piece of code probably makes a
call that looks something like
qp->timer.function(qp->timer.data);
.... and this will invoke the ip_expire() function.
2) how following casting occurs in ip_expire(unsigned long arg)
struct ipq *qp = (struct ipq *) arg;
how a unsigned long be converted to structure?
First, the `unsigned long' is not being converted to a
struct. It's being converted to a struct pointer, which is
a very different thing.
Second, the conversion is unsafe. Converting an integer
type to a pointer gives an implementation-defined result that
might not be useful at all. Some sloppy code (like the above)
assumes that these conversions will simply "preserve all the
bits" (if the integer has at least as many bits as a pointer),
but the C language does not guarantee this. The code relies
on the quirks of a particular compiler in a particular environment,
and is suspect in all other environments.
Note the corresponding conversion in the assignment to
`qp->timer.data' (which probably winds up being passed to
ip_expire() as its argument). This takes the pointer `qp' and
converts it to an `unsigned long' -- and again, the result is
implementation-defined and might not be useful.
Code like this has a nasty habit of working just fine for
a long time on many machines, and then comes the day when it's
ported to a machine of a different kind and things suddenly
go wrong. We went through this when implementations started
using 32 bits for `int' instead of 16, and we went through it
again when 64-bit quantities came along -- and it looks like
this chunk of code never learned those hard lessons.
--
Eric Sosman
es*****@acm-dot-org.invalid