views:

414

answers:

6

I am trying to understand what the following line of the worst-ever-seen C code (from uboot project) mean:

rc = ((ulong (*)(bd_t *, int, char *[]))addr) (bd, --argc, &argv[1]);

What is it? A function call? Can it be more readable?

Thanks in advance for your help!

+12  A: 

It casts addr to a function pointer which accepts (bd_t *, int, char *[]) as arguments and returns a long, then invokes it with the arguments (bd, --argc, &argv[1]).

Mike Weller
Right. And to answer the second question, no, it can not be made more readable.
Jason
@Jason: Sure it can (and should), see unwind's answer.
T.J. Crowder
Shrug. To a C programmer it's perfectly readable.
Stephen Canon
Finnegan's Wake is also perfectly readable, but extracting meaning from it is substantially difficult.
Adam Crossland
@T.J. Crowder: That just moves the perceived unreadability elsewhere. (To be clear, I'm not agreeing that either version is unreadable. Just that if someone were to find the original unreadable, offloading part of the unreadability elsewhere doesn't reduce the unreadability.)
Jason
@Stephen: Plenty of C programmers, particularly newer ones, don't have to deal with function pointers often at all. Moreover, it's much better programming practice to declare the pointer type (if you're going to have to use one) in the same header where you declare the function, so that if you need to change the function, you don't break every individual hand-coded cast. Maintenance 101, in my view.
T.J. Crowder
I don't see using a typedef as improving readability, but if the function pointer type is used in multiple places then it makes sense to use one to remove the duplication.However, if the function pointer type is a one-off then I don't see a problem with using it inline.My two cents.
Mike Weller
@Jason: I disagree, for the reasons in my comment to Stephen. But it's all good, smart people can disagree with each other. :-)
T.J. Crowder
@T.J. Crowder: I completely agree with your maintenance comments; that is a very good reason to provide such a `typedef`. I will agree that we can agreeably disagree on whether or not it improves the readability to someone that doesn't find the original version readable. :-)
Jason
Offloading *hard part* to typedef helps in scenarios where you read code, but do not want to inspect in detail this particular bit. With typedef it looks like ordinary function call and you can "parse" it quicker. In contrast this can be disadvatge when you are looking for strange errors if - for example - your function pointer is not set right. Good naming is essential when doing typedef (like fp_<name> or something) so you can detect function pointers if you need to.
MaR
+2  A: 

ulong (*)(bd_t *, int, char *[]) is the type of a function that takes a pointer to a bd_t, an int, and a pointer to a char array, and returns a ulong.

The code is casting addr to such a function, and then calling it with bd, --argc, and &argv[1] as parameters, and assigning the result to rc.

Graeme Perrow
+33  A: 

Yes, it's a function call.

It casts the value in addr to a function pointer which accepts (bd_t *, int, char *[]) as arguments and returns a ulong, and calls the function. It could be sugared into:

typedef ulong (*bd_function)(bd_t *bd, int argc, char *argv[]);

bd_function bdfunc = (bd_function) addr;

rc = bdfunc(bd, --argc, &argv[1]);

This might be overkill, to introduce a typedef if this only happens once, but I feel it helps a lot to be able to look at the function pointer's type separately.

unwind
Since the typedef makes the thing readable, it isn't overkill.
David Thornley
It isn't overkill in the same way that anitbiotics aren't an overreaction to infection.
Adam Crossland
+1  A: 

You're typecasting "addr" to a pointer to a function returning a ulong that takes a bd_t *, an int and a char *[] as parameters, and then calling the function with the parameters bd, --argc, &argv [1].

Skizz
+2  A: 

addr must be the location in memory to a function that looks like

ulong *funcname(bd_t*, int, char*[])

and it's being called with the paramerers like

rc = funcname(bd, --argc, &argv[1]);
John Boker
+4  A: 

Not a direct answer to your question, but might be of interest:

Start at the variable name (or innermost construct if no identifier is present. Look right without jumping over a right parenthesis; say what you see. Look left again without jumping over a parenthesis; say what you see. Jump out a level of parentheses if any. Look right; say what you see. Look left; say what you see. Continue in this manner until you say the variable type or return type.

Mitch Wheat
Would the downvoter please leave a comment. Thanks.
Mitch Wheat
LOL. good advise :)
psihodelia