page 120 K&R

M

mdh

Hi All,
this little nonsense function is an attempt to understand function
pointers.

/*********/

#include <stdio.h>

void p(int);

int main (int argc, const char * argv[]) {
void (*q)(int) = p;
q(50); /* Question about this */
return 0;
}


void p(int i){

int j = i, k=1;

while ( i-- > 0)
printf("Print me %d times (iteration %2d)\n", j, k++);
}

/*****/

From my reading on p 120 I expected the call to p to be *q(50) and not
q(50) but *q gives an error. Paraphrasing K&R, q is a pointer to a
function, *q is the function and (*q)( arguments) is the call to it.
Could someone explain what I am missing?
Thank you.
 
U

user923005

Hi All,
this little nonsense function is an attempt to understand function
pointers.

/*********/

#include <stdio.h>

void p(int);

int main (int argc, const char * argv[]) {
void (*q)(int) = p;
q(50); /* Question about this */
return 0;

}

void p(int i){

int j = i, k=1;

while ( i-- > 0)
printf("Print me %d times (iteration %2d)\n", j, k++);
}

/*****/

From my reading on p 120 I expected the call to p to be *q(50) and not
q(50) but *q gives an error. Paraphrasing K&R, q is a pointer to a
function, *q is the function and (*q)( arguments) is the call to it.
Could someone explain what I am missing?

C:\tmp>oops
entered p with 7
Print me 7 times (iteration 1)
Print me 7 times (iteration 2)
Print me 7 times (iteration 3)
Print me 7 times (iteration 4)
Print me 7 times (iteration 5)
Print me 7 times (iteration 6)
Print me 7 times (iteration 7)
entered p with 3
Print me 3 times (iteration 1)
Print me 3 times (iteration 2)
Print me 3 times (iteration 3)
entered p with 4
Print me 4 times (iteration 1)
Print me 4 times (iteration 2)
Print me 4 times (iteration 3)
Print me 4 times (iteration 4)

C:\tmp>type oops.c
#include <stdio.h>

void p(int);

int main(int argc, const char *argv[])
{
void (*q) (int) = p;
q(7);
(*q) (3);
p(4);
return 0;
}

void p(int i)
{
int j = i,
k = 1;
printf("entered %s with %d\n", __FUNCTION__, i);
while (i-- > 0)
printf("Print me %d times (iteration %2d)\n", j, k++);
}

/*****/
 
F

Flash Gordon

mdh wrote, On 27/11/07 06:02:
Hi All,
this little nonsense function is an attempt to understand function
pointers.

/*********/

#include <stdio.h>

void p(int);

int main (int argc, const char * argv[]) {
void (*q)(int) = p;
q(50); /* Question about this */

From my reading on p 120 I expected the call to p to be *q(50) and not
q(50) but *q gives an error. Paraphrasing K&R, q is a pointer to a
function, *q is the function and (*q)( arguments) is the call to it.
Could someone explain what I am missing?

You are missing a few things. The first is that in most situations the
name of a function "decays" to a function pointer (which is why you did
not need to use & to take the address of p) and when you are calling a
function you are actually calling it via the function pointer. Obviously
q is a function pointer so as calls are via function pointers you can
call through it.

Next is that () binds more tightly to q than *, to *q(50) means call q
passing 50 to it and dereference the (pointer) value returned by q,
which is obviously an error as q does not return any value, let alone a
pointer. So you need (*q)(50) to dereference q and then call the
function it points to. Even so this only works because of the strange
rules of C which mean that having dereferenced q it then gets
automatically converted back to a function pointer. As a side effect you
could just as well use (*******q)(50). It also makes applying & to a
function name pointless.
 
R

Richard Heathfield

Flash Gordon said:

So you need (*q)(50) to dereference q and then call the
function it points to. Even so this only works because of the strange
rules of C which mean that having dereferenced q it then gets
automatically converted back to a function pointer. As a side effect you
could just as well use (*******q)(50). It also makes applying & to a
function name pointless.

Just for completeness: you can omit the (*) completely if you like; q(50)
and (*q)(50) both work just fine. I happen to prefer the (*q)(50) syntax,
as it documents the fact that q is a function pointer, thus telling the
maintenance programmer that there's no point in searching the codebase for
the source code to q.
 
M

mdh

mdh wrote, On 27/11/07 06:02:
int main (int argc, const char * argv[]) {
void (*q)(int) = p;
q(50); /* Question about this */
<snip>


You are missing a few things. The first is that in most situations the
name of a function "decays" to a function pointer (which is why you did
not need to use & to take the address of p) and when you are calling a
function you are actually calling it via the function pointer.

Let me make sure I understand you. Once a function is defined, the
address of that function becomes equivalent to it's name. So any
reference to that function is simply a reference to it's address.
(Kind of similar to the way an array is referenced?)

Next is that () binds more tightly to q than *, to *q(50) means call q
passing 50 to it and dereference the (pointer) value returned by q,
which is obviously an error


I keep getting tripped up by associativity....thank you.

as q does not return any value, let alone a
pointer. So you need (*q)(50) to dereference q and then call the
function it points to. Even so this only works because of the strange
rules of C which mean that having dereferenced q it then gets
automatically converted back to a function pointer.


Ok...thank you. One step closer to nirvana!!!
 
M

mdh

C:\tmp>oops
entered p with 7
Print me 7 times (iteration 1)
Print me 7 times (iteration 2)
Print me 7 times (iteration 3)
Print me 7 times (iteration 4)
Print me 7 times (iteration 5)
Print me 7 times (iteration 6)
Print me 7 times (iteration 7)
entered p with 3
Print me 3 times (iteration 1)
Print me 3 times (iteration 2)
Print me 3 times (iteration 3)
entered p with 4
Print me 4 times (iteration 1)
Print me 4 times (iteration 2)
Print me 4 times (iteration 3)
Print me 4 times (iteration 4)

C:\tmp>type oops.c
#include <stdio.h>

void p(int);

int main(int argc, const char *argv[])
{
void (*q) (int) = p;
q(7);
(*q) (3);
p(4);
return 0;

}

void p(int i)
{
int j = i,
k = 1;
printf("entered %s with %d\n", __FUNCTION__, i);
while (i-- > 0)
printf("Print me %d times (iteration %2d)\n", j, k++);

}

/*****/


thank you
 
M

mdh

Flash Gordon said:



Just for completeness: you can omit the (*) completely if you like; q(50)
and (*q)(50) both work just fine. I happen to prefer the (*q)(50) syntax,
as it documents the fact that q is a function pointer, thus telling the
maintenance programmer that there's no point in searching the codebase for
the source code to q.


thank you Richard.
 
F

Flash Gordon

mdh wrote, On 27/11/07 09:21:
mdh wrote, On 27/11/07 06:02:
int main (int argc, const char * argv[]) {
void (*q)(int) = p;
q(50); /* Question about this */ <snip>

You are missing a few things. The first is that in most situations the
name of a function "decays" to a function pointer (which is why you did
not need to use & to take the address of p) and when you are calling a
function you are actually calling it via the function pointer.

Let me make sure I understand you. Once a function is defined, the
address of that function becomes equivalent to it's name. So any
reference to that function is simply a reference to it's address.
(Kind of similar to the way an array is referenced?)

<snip>

Yes, I believe the times this does not happen are also the for arrays
and function names. Note that one difference is that an array name
"decays" to a pointer to its first element where as a function name
gives a pointer to the function as a whole, an important difference.
 
F

Flash Gordon

Richard Heathfield wrote, On 27/11/07 09:19:
Flash Gordon said:



Just for completeness: you can omit the (*) completely if you like; q(50)

That q(50) is valid was covered by the first paragraph which you did not
quote, including the reason it is valid.
and (*q)(50) both work just fine. I happen to prefer the (*q)(50) syntax,
as it documents the fact that q is a function pointer, thus telling the
maintenance programmer that there's no point in searching the codebase for
the source code to q.

Well, if the maintenance programmer searches for the definition of q
they should find the definition of the function pointer.
 
M

mdh

Note that one difference is that an array name
"decays" to a pointer to its first element where as a function name
gives a pointer to the function as a whole, an important difference.


Just curious. Why is it that the pointer to a function decays to a
pointer for the whole function vs the address of the first ?string. As
a guess, because there is not an easy way to indicate the terminal
element?
 
R

Richard Heathfield

Flash Gordon said:
Richard Heathfield wrote, On 27/11/07 09:19:

That q(50) is valid was covered by the first paragraph which you did not
quote, including the reason it is valid.

On re-reading, I discover that you're right, although I had to think about
it and read it very carefully to determine this. I apologise for
attempting to complete the complete. :)
Well, if the maintenance programmer searches for the definition of q
they should find the definition of the function pointer.

Yes, that's certainly true. Nevertheless, by using the indirection syntax,
we (might) save them the trouble of searching in the first place.
 
R

Richard Heathfield

mdh said:
Just curious. Why is it that the pointer to a function decays to a
pointer for the whole function vs the address of the first ?string.

What string is that? The first line of the function's C source code? But -
assuming for the moment that we're using a compiler rather than an
interpreter - the source code need no longer be visible by the time the
program is running. It might not even exist any more.

If that isn't the string you meant, what string did you mean?
 
S

santosh

mdh said:
Just curious. Why is it that the pointer to a function decays to a
pointer for the whole function vs the address of the first ?string.

What string. The first string in the source code for the function. But
that is useless at runtime.

Under most computers a pointer to a function holds the address of the
first machine instruction for that function. So, in a way, it is
analogous to the case with arrays, where the array name "decays" to a
pointer to the address of it's first element.

In fact with a simple cast you can even treat an array like a function
and attempt to execute it or treat a function like an array and examine
it's data. Of course doing any of this falls outside the scope of the
standard and the operating system may prevent you from executing data.
As a guess, because there is not an easy way to indicate the terminal
element?

No. Usually code has no "terminal element". It continues until a jump
instruction or a halt instruction or a trap instruction or something
like that.
 
M

mdh

mdh said:



What string is that?

The wrong string, I am rapidly deducing!! :)

Seriously though, I was just trying to understand why a string array
would decay to a pointer to the first character, and a function
pointer decays to the whole function. I assumed that part of the
answer is that one is able to determine the termination of the string
array by the NULL character.I suppose in a function, one has an array
of character pointers, now that I think about it. But that does bring
one back to the original query of why the pointer type is one of
"pointer to whole-function"
 
M

Mark Bluemel

mdh said:
The wrong string, I am rapidly deducing!! :)

Seriously though, I was just trying to understand why a string array
would decay to a pointer to the first character, and a function
pointer decays to the whole function. I assumed that part of the
answer is that one is able to determine the termination of the string
array by the NULL character.I suppose in a function, one has an array
of character pointers, now that I think about it. But that does bring
one back to the original query of why the pointer type is one of
"pointer to whole-function"
Because you can usefully do something with part of an array, but you
can't usefully do anything with part of a function - it's not really
decomposable.
 
J

James Kuyper

mdh wrote:
....
Seriously though, I was just trying to understand why a string array
would decay to a pointer to the first character, and a function
pointer decays to the whole function. I assumed that part of the
answer is that one is able to determine the termination of the string
array by the NULL character.I suppose in a function, one has an array
of character pointers, now that I think about it. But that does bring

I get the impression that you think a function pointer points at an
in-memory copy of the source code for that function. This is generally
not the case. It might be true in an interpreted version of C, though
even then it's far more likely to point at some interpreter-specific
partially-compiled representation of the source code. However, in a
compiled version of C the function pointer typically points at the entry
point for a block of machine code.

The fundamental reason why a pointer to a function is only a pointer to
the entire function is that the only thing you can do with a pointer to
a function is call the the function. A function has no accessible parts.
 
M

mdh

The fundamental reason why a pointer to a function is only a pointer to
the entire function is that the only thing you can do with a pointer to
a function is call the the function. A function has no accessible parts.

Thank you...makes sense...I was trying to read to much into it...as
usual!!
 
C

Chris Dollin

Richard said:
Flash Gordon said:

Yes, that's certainly true. Nevertheless, by using the indirection syntax,
we (might) save them the trouble of searching in the first place.

(fx:broken-record) Small functions => trivial searching.
 
C

Chris Dollin

mdh said:
Just curious. Why is it that the pointer to a function decays to a
pointer for the whole function vs the address of the first ?string.

What first string?

A C function is a single unitary object\\\\\\entity; it doesn't have
parts. [Unlike, say, a Pop11 function, from which you can extract
eg its name, if it has one, and its frozen arguments, if it's a closure;
but not its source or VM or IM code.]

The only thing to point at is the entire function.
 
R

Richard Heathfield

Chris Dollin said:
(fx:broken-record) Small functions => trivial searching.

Very true.

Alas, we don't always write small functions, do we? Much as we might intend
to.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top