Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

In struct MalVal[0], the values f0 through f20, where each holds a pointer-to-functions of the corresponding arity, live in a big (multifacted?) union. Using arg_cnt, the switch assigns func to the appropriate value in mv->val using the appropriate cast.

For example, when arg_cnt is 2, mv->val.f2 receives func converted to void * (* )(void* , void* ), that is, pointer to a function that accepts two parameters of type pointer-to-void and returns pointer-to-void. [Weird spacing to effectively escape the asterisks that would otherwise be treated as italicizing markup.]

C permits conversion between pointer-to-function of one type to pointer-to-function of another type. The inverse is also defined, and the resulting pointer will compare equal to the original. However, calling a function through a pointer-to-function where the types do not match invokes undefined behavior.

[0]: https://github.com/kanaka/mal/blob/master/c/types.h#L85



This could be made massively less ugly and more readable by typedef'ing the function pointer types by the way. Then one could just write:

  case 13: mv->val.f13 = (F13)func; break;
As a C programmer I got to say people in general don't use typedef for function pointer types often enough. The types are so ugly and verbose, they should be typedef'ed by default.


I think the primary argument that I've heard against typedefing function pointers is you can end up obfuscating what is happening and end up making the code less readable/harder to maintain in the future.


This code could take advantage of the fact that the type is a union.

One can bend the rules of prim-and-proper well-defined ISO C just a little bit and assign to the simplest function pointer, taking advantage of all function pointers having the same representation on every machine known to mortal hacker, and all being overlaid by the union. Thus all the cases collapse down to this:

   mv->val.u.f0 = (void (*)(void)) func;
done. Now if this is 13 arguments, then strictly speaking, accessing mv->val.uf13 is not well-defined behavior. That's only going to be problem when it actually doesn't work, though. A big problem, then. :)


I can respect the author taking the trouble to avoid undefined behavior. Technically correct is the best kind of correct.


That sort of love affair with ISO gospel lands on the rocks as soon as your Lisp stuffs a couple of tag bits into a C pointer.


I look forwards to your pull request! One challenge you'll run into is that (as I recall) the Boehm GC linkage no longer works with newer versions of Boehm.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: