|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
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. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On Nov 26, 10:02 pm, mdh <m...@comcast.net> wrote:
> 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++); } /*****/ |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
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 */ <snip> > 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. -- Flash Gordon |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
Flash Gordon said:
<snip> > 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. -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Nov 27, 12:51 am, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> 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!!! |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
On Nov 26, 11:01 pm, user923005 <dcor...@connx.com> wrote:
> On Nov 26, 10:02 pm, mdh <m...@comcast.net> wrote: > > > > > > 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 |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Nov 27, 1:19 am, Richard Heathfield <r...@see.sig.invalid> wrote:
> Flash Gordon said: > > <snip> > > > 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 ....snip. > > 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. |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
mdh wrote, On 27/11/07 09:21:
> On Nov 27, 12:51 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: >> 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. -- Flash Gordon |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
Richard Heathfield wrote, On 27/11/07 09:19:
> Flash Gordon said: > > <snip> > >> 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) 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. -- Flash Gordon |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> 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? |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
Flash Gordon said:
> Richard Heathfield wrote, On 27/11/07 09:19: >> >> 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. 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. :-) > >> 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. Yes, that's certainly true. Nevertheless, by using the indirection syntax, we (might) save them the trouble of searching in the first place. -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
mdh said:
> On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: >> 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. 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? -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
In article
<b8545f25-ceb3-4f63-b931-2ac1667c2bc4@e6g2000prf.googlegroups.com>, mdh <mdeh@comcast.net> wrote on Tuesday 27 Nov 2007 5:58 pm: > On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: >> 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. 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. |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
On Nov 27, 5:32 am, Richard Heathfield <r...@see.sig.invalid> wrote:
> mdh said: > > > On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: > >> 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. > > 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" |
|
|
|
#15 |
|
Messages: n/a
Hébergeur: |
mdh wrote:
> On Nov 27, 5:32 am, Richard Heathfield <r...@see.sig.invalid> wrote: >> mdh said: >> >>> On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: >>>> 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. >> 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" > > 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. |
|
|
|
#16 |
|
Messages: n/a
Hébergeur: |
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. |
|
|
|
#17 |
|
Messages: n/a
Hébergeur: |
On Nov 27, 5:59 am, James Kuyper <jameskuy...@verizon.net> wrote:
> > 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!! |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
Richard Heathfield wrote:
> Flash Gordon said: >>> 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. > > 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. -- Chris "hence, CDs" Dollin Hewlett-Packard Limited registered no: registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England |
|
|
|
#19 |
|
Messages: n/a
Hébergeur: |
mdh wrote:
> On Nov 27, 2:34 am, Flash Gordon <s...@flash-gordon.me.uk> wrote: >> 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. 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. -- Chris "the finger and the moon" Dollin Hewlett-Packard Limited registered office: Cain Road, Bracknell, registered no: 690597 England Berks RG12 1HN |
|
|
|
#20 |
|
Messages: n/a
Hébergeur: |
Chris Dollin said:
> Richard Heathfield wrote: > >> Flash Gordon said: > >>>> 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. >> >> 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. Very true. Alas, we don't always write small functions, do we? Much as we might intend to. -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
|
|
|
#21 |
|
Messages: n/a
Hébergeur: |
Richard Heathfield wrote:
> Chris Dollin said: > >> Richard Heathfield wrote: >> >>> Flash Gordon said: >> >>>>> 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. >>> >>> 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. > > Very true. > > Alas, we don't always write small functions, do we? Perhaps not always (he said, remembering the 800-line monster) -- but usually, yes. > Much as we might intend to. And when it turns out that we lose track of names within that function, we carve it up into legible pieces, don't we? -- Chris "cackling, with scissors" Dollin Hewlett-Packard Limited Cain Road, Bracknell, registered no: registered office: Berks RG12 1HN 690597 England |
|
|
|
#22 |
|
Messages: n/a
Hébergeur: |
Richard Heathfield <rjh@see.sig.invalid> writes:
> Chris Dollin said: > > > Richard Heathfield wrote: > > > >> Flash Gordon said: > > > >>>> 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. > >> > >> 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. > > Very true. > > Alas, we don't always write small functions, do we? Much as we might intend > to. Functions are written small... and then some grow too much before refactoring take place. -- Jean-Marc |
|
|
|
#23 |
|
Messages: n/a
Hébergeur: |
Chris Dollin said:
> Richard Heathfield wrote: > <snip> >> >> Alas, we don't always write small functions, do we? > > Perhaps not always (he said, remembering the 800-line monster) -- but > usually, yes. > >> Much as we might intend to. > > And when it turns out that we lose track of names within that function, > we carve it up into legible pieces, don't we? Sometimes. :-) -- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
|
|
|
#24 |
|
Messages: n/a
Hébergeur: |
Richard Heathfield wrote, On 27/11/07 13:29:
> Flash Gordon said: > >> Richard Heathfield wrote, On 27/11/07 09:19: >>> 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. > > 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. :-) Think of it as clarification instead of completion. If you had to think hard about it then that point was probably not clear enough. >>> 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. > > Yes, that's certainly true. Nevertheless, by using the indirection syntax, > we (might) save them the trouble of searching in the first place. I have to say that in all of the instances where I have used variable of function pointer type it has been either clear from context that it would be a function pointer or it has been none of the callers business that it is not actually the function (yes, there is a specific reason in a library I use to be able to replace the called function behind the application programmers back, and no it is not my design). -- Flash Gordon |
|
|
|
#25 |
|
Messages: n/a
Hébergeur: |
Chris Dollin wrote:
> ... > And when it turns out that we lose track of names within that function, > we carve it up into legible pieces, don't we? > ... In 9 cases out of 10 "losing track of names within function" is a consequence of the devastatingly bad, but still widely used practice of declaring all names at the very beginning of the function. Even in C89/90 it was possible to declare names close to the point where they are used, not even mentioning C99. Small functions are overrated ![]() -- Best regards, Andrey Tarasevich |
|
![]() |
| Outils de la discussion | |
|
|