Fog Creek Software
Discussion Board




WAS: Becoming a C _developer_

In the earlier thread, Quickie asked,

"Write a function in C that returns a function that adds x to its argument."

http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=146457

Here's my go at it. It still gives me 2 link errors though. Comments appreciated.

[CODE]
/*Write a function in C that returns a
function that adds x to its argument

  x in this case is 2
*/

#include <stdio.h>

int Add2(int);
int (*fnptr)(int);
int (*fn(void))(int);


int main(void)
{
    fnptr=fn;
    printf("%d", (*fnptr)(3));
}

    
int Add2(int a)
{
    return a+2;
}

void ptr(void)
{
    return &Add2;
}
[/CODE]

Sathyaish Chakravarthy
Thursday, June 10, 2004


Sorry for the typos. Here's the modified version. It compiles, links, but prints junk. So it basically doesn't do what it was supposed to do. Comments welcome.

[CODE]
/*Write a function in C that returns a
function that adds x to its argument

  x in this case is 2
*/

#include <stdio.h>

int Add2(int);
typedef int(*fnptr)(int);
int (*fn(void))(int);


int main(void)
{
    int (*fnptr)(int);
    fnptr=fn;
    printf("%d", (*fnptr)(3));
}

    
int Add2(int a)
{
    return a+2;
}

fnptr fn(void)
{
    return &Add2;
}
[/CODE]

Sathyaish Chakravarthy
Thursday, June 10, 2004

fnptr=fn;
printf("%d", (*fnptr)(3))

You are passing 3 to the function fn which does not take any parameters.

What exactly is it that you are trying to do?

Code Monkey
Thursday, June 10, 2004


I don't know if it is right, but...

fnptr=fn;
I call the function fn that returns a fnptr type, and the return value is assigned to the function pointer fnptr.


printf("%d", (*fnptr)(3));
Now that fnptr contains the address of Add2 since fn retuns &Add2, I am trying to call Add2 using the value in *fnptr with the argument 3.

Where am I going wrong?

Sathyaish Chakravarthy
Thursday, June 10, 2004


Old habits die hard.

fnptr=fn;

My VB head was accustumed to calling a function without the paranthesis. It was just this lil thing, which should've been.

fnptr=fn();

Eureka!

Sathyaish Chakravarthy
Thursday, June 10, 2004

Search for closure on google.

Tom Vu
Thursday, June 10, 2004


http://www.google.com/search?q=closure&sourceid=opera&num=0&ie=utf-8&oe=utf-8


All the way for you, Tom Vu.

No, no, for the rythm,
All the way for you,
<space><space> Tom Vu.

:-)

Sathyaish Chakravarthy
Thursday, June 10, 2004

What book are you reading? I read about 60% of the book Tech your self C in 24 hours and it talked about having a function as parameter of a function.

The book: http://www.amazon.com/exec/obidos/tg/detail/-/067231861X/104-3057560-7147904?v=glance

Somorone
Friday, June 11, 2004


Because I am at the office, at the moment, I am following a tutorial on http://function-pointer.org.

>I read about 60% of the book Tech your self C in 24 hours and it talked about having a function as parameter of a function.

????

http://www.codeguru.com/forum/showthread.php?s=&threadid=298165

Sathyaish Chakravarthy
Friday, June 11, 2004


BTW Somorone, the links you gave me the last time were all excellent. One of them I guess was dead, but that's ok, you mentioned that. Otherwise, they were all a treat. Thanks!

Sathyaish Chakravarthy
Friday, June 11, 2004

int (*fn(void))(int);

Basically a pointer to a function
that takes a void( nothing) and ....
returns a pointer to a function that..
takes an int and...
returns an int...

Use Right- left Rule

Ben
Friday, June 11, 2004

Er, nice try, but not quite.

First, the problem said "x", not "2".  (Imagine how many CS problems would be trivial if we were allowed to say "x in this case is 2", and then solve that one case!)

Second, you're assuming the argument is always an int, which the problem didn't specify.  (If you're trying to do Paul Graham's accumulator generator, he makes it clear that you have to deal with numbers, not integers.)

It's 3:30am and my mind is a little mushy from a long day of hacking, but I'm not sure if it's possible to do in pure C.  At the least, you'd have to make some assumptions about the range and precision of numbers in C.

Here's the big problem, as I see it: you'd need a function make_fun(x) which returned a pointer to a function.  Trouble is, you have to make a new function at runtime: make_fun(-1) and make_fun(M_PI) have to return different functions.  I don't know how to do that in C.  Maybe if you called the C compiler again, or used a dummy function as a prototype, modified that on-disk, and dlopen()'d it ... bunch of ways I can think of, all pretty nasty.  (Which basically goes to prove his point about some languages being more powerful than others.)

Z
Friday, June 11, 2004

Rather than dynamically generating the functions, can you just write a function for each number type, figure out what type is passed in, then call the appropriate function from a lookup table of sorts?

Though, I don't code C, so take the above suggestion with a grain of salt.

Andrew Hurst
Friday, June 11, 2004

Seems like a perfect job for templates and function objects.

Alex
Friday, June 11, 2004

Except C has neither templates nor objects. :)

Michael Eisenberg
Friday, June 11, 2004

I think the poster who asked (sarcastically), "write a function that returns a pointer to a function that adds a number" was being unfair.

You know, if you're going to ask specifically for "a pointer to a function", that can't be done in C. Why? Because C (and C++) doesn't instantiate code, only data. All code is static, even class methods are really static.

But then again, does Lisp return "a pointer" to a function? No, it returns an object, an adder, whatever, but not a dumb "pointer" to a function. So the phrasing of the question was unfair.

Yes, I can return an object (even in C, easier in C++) that does what you need; it could contain the "add-to" value, a pointer to some function that does the adding, or whatever.

C is intended for efficiency -- it's the language to use when you're counting every byte. If you want a function that returns something as complex as a "function that adds numbers" crammed into the space of 4 bytes, sorry, you're just being unfair. I'm quite sure the object that Lisp returns is larger than 4 bytes.

Not sure I made my point, just making some remarks anyway.

Alex
Friday, June 11, 2004

Maybe it's unfair in a certain sense, but I think it's a great question anyway--one that really helps you understand C as a language.

And returning a pointer to a function is perfectly easy in C. The question is what the pointer is going to point to!

Michael Eisenberg
Friday, June 11, 2004

"If you want a function that returns something as complex as a "function that adds numbers" crammed into the space of 4 bytes, sorry, you're just being unfair. I'm quite sure the object that Lisp returns is larger than 4 bytes."

I don't think it's unfair: I hacked assembly on my C=64 back in the day, and I could write an assembly function that returned a pointer to a function (and there it'd only be 2 bytes!).  You just need to be able to allocate a new function in memory somewhere, which C doesn't allow (which doesn't necessarily mean C is bad, that was just their design decision).

In fact, I think you're being unfair.  Yes, the *object* Lisp returns is larger than 4 bytes -- but the C function would probably be larger than 4 bytes, as well.  You have to decide if you're measuring the pointer to the object (4 bytes), or the function itself (however long your function is).  When Lisp returns a pointer to an object it's also 4 bytes (on a 32-bit system), just like C.

Z
Friday, June 11, 2004

I just realized you can do it in "almost" C.

If ATL can create code thunks and get away with it, so can we.

Just copy of the body of a "generic" adder function to malloc'ed memory, replace the immediate value with your number, and voila.

Come to think of it, the user can even free() the returned pointer when he's done.

Alex
Saturday, June 12, 2004

*  Recent Topics

*  Fog Creek Home