int foo()
int x;
int y;
{ return x + y; }
Perfectly legal C, if not an old archaic and seldom used syntax. I saw it in some proprietary code, so, no, I cannot provide a link. It was odd, but worked for what it was trying to do.It pays to know the language you work in, not to write things like this, but to understand on the off chance you encounter it in the wild.
Edit, I may be wrong on the syntax, it might be:
int foo(x, y)
int x;
int y;
{ return x + y; }
I dont have the ISO spec in front of me, but one of these should work.Rather it should look like this:
int foo(x, y)
int x;
int y;
{ return x + y; }
x and y would be assumed to be int in the absence of the type specifiers, so in this case they're optional. foo(x, y) { return x + y; }If we stick to standard C, all calls are statically determined, so your only option is to switch among different call expressions, like:
switch (nargs) {
case 0: return f();
case 1: return f(a[0]);
case 2: return f(a[0], a[1]);
...
}
Here, if the f pointer is under-declared, it saves you some casting.You can use a union:
struct fun {
int nargs;
union {
int (*ptr0)(void);
int (*ptr1)(valtype);
int (*ptr2)(valtype, valtype);
...
} fn;
}
Then: switch (f->nargs) {
case 0: return f->fn.ptr0();
case 1: return f->fn.ptr1(arg[0]);
...
}
Now there is a modicum of type checking. When you create the "struct fun" object, you may be able to take the address of a function that is compatible with one of the ptr's, and assing it to the correct union member without having to use a cast. If you record the number of arguments correctly, it won't be misused.POSIX generaly has very little to say about C matters; for the most part it defers to ISO C by normative reference.
Off the top of my head, because POSIX specifies dlopen and dlsym, that pretty much requires function pointers have to have a common representation convertible between void * and back.
One of my coworkers could defeat any idea for a new optimization with "well, what about unions?" which would typically complicate things quickly...
I'm not sure I follow: they would thwart your attempts at optimizing things by talking about unions?
Say we have a really contrived function that works with two pointers A and B to the same union type. The compiler cannot prove that A and B are distinct. The function evaluates A->x = expr, and also B->y in several places. Since A and B might be the same pointer, the assignment has to be regarded as clobbering B->y, which interferes with CSE of B->y and register caching.
As of C99, a possible solution here would be to declare the pointers restrict; then the compiler assumes they don't overlap: A->x has nothing to do with B->y.
If a struct is used, then x and y are different members and have nothing to do with each other for that reason, needless to say, even if A and B are the same pointer.
Most of the code surrounding this won't contain assignments into the union, so it won't impact optimization.
In an interpreted language I wrote this kind of union is initialized when a function object comes to life, and then not mutated again.
The union is necessary because a struct would blow up the size of the object significantly (and then it wouldn't fit into the GC heap cell size, requiring an additional piece of malloced memory).
Main takes argc and argv, but it's idiomatic to omit them if unused.
[0] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2346.pdf
case 123 ... 456:
Switching on strings is another thing people have been wanting for half a century. It would seep up many programs, because most programmers don't bother to generate a perfect hash or a carefully-balanced tree of "if".
It works because with the way the C ABI works on all platforms I'm aware of, extra arguments passed to the function can be completely ignored by the function with no ill effects, so the fact that _start actually invokes main with argc and argv can be ignored by main.
Which is to say, you could also write this as
int main(void) { return 0; }
and that would work equally as well. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR, int)
(where WINAPI is just a macro for __stdcall)I also found a reference saying you can in fact use `int main()` if you want to, in a GUI subsystem Windows app, by using the Microsoft linker options /subsystem:windows /ENTRY:mainCRTStartup, but in that case you're not writing a stdcall function anymore.
EDIT: I guess I should clarify, my previous comment was talking about cdecl functions, i.e. the default calling convention in C.