Prefer T foo(void) in C because that's the declaration that actually introduces, into the scope, information about the parameter list.
T foo() is a deprecated old style from before ANSI C 1989 which declares foo in a way that is mum about how many arguments there are and what their types are.
(void) is actually an ANSI C invention. C++ adopted this for better C compatibility. (Yes, C++ did that once upon a time!) Then some C++ coders started doing silly things like myclass::myclass(void): something that would never be processed with a C compiler.
(void) is ugly; it would be a productive change in C to do away with K&R declarations and make () equivalent to (void) like C++ did some three decades ago.
How often do you need to do that? I feel like I never have, and I think feel like it's a rare enough use as that it shouldn't be the default behavior, but maybe I haven't written enough C.
I have actually run across code in the wild along the lines of:
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.
I use it sometimes for callbacks that take similar but not exactly the same arguments, f.e. containers for pointers that can have an optional "release" function pointer that is called to release all pointers in the container and can be assigned to "free" for raw data, or object specific destructors like "free_bitmap" or "free_sound" or even "free_container" (so having a container with other containers inside that may have their own "release" functions).
It shouldn't be the default, but I use it occasionally when you have a function pointer and need to call it with a set of arguments that you get at runtime.
There isn't any way to do this in ISO C. Libraries like libffcall and libffi exist for dynamically building a C argument list and calling it.
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.
Your idea to use a union of function pointers also allows a much broader range of function parameter types to be used. When you call a function that used a K&R declaration, the arguments are subject to default promotion e.g. short to int, so you can't call "int f(short)" if it is only declared "int f()". Your idea doesn't have this problem.
Here, the union is being used as a space-saving structure. We only need to store one pointer, but it can be of different types. We access the same one that we most recently stored.
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).
Compilers that allow type punning through a union have to basically consider the access to a member of the union to have an effect on any other member. It's conceivable that there are edge cases where that consideration could hamper the optimization of a code which uses unions without perpetrating any sort of type punning. Hmm, like what?
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.
Given that this is C, can the compiler prove in any case that two pointers are distinct? When you're dealing with a structure, it could still be the case that A = B + sizeof(structure.x) (+/- padding).
Yes, I know this: I'm relying POSIX's guarantees and not what ISO C mandates (also truth be told I usually do this in Objective-C, but that doesn't actually change anything significantly). Unfortunately I get a function pointer and need forward essentially anything, so I'm not going to have any sort of type safety at all…
What guarantees does POSIX make about calling functions that are not in ISO C? I'm curious.
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.
This is irrelevant; this is the function definition, which means the compiler knows this function takes zero arguments.
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.
I've never done Windows programming but AFAICT you don't use `int main()` on Win32 anyway, you write something like
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.
That's a special case though and unrelated to ().
Like it's also explicitly allowed to omit a return statement in main altogether, which implies a return 0.
That was added in C99; previously, "falling off" the end of main without a return statement resulted in an indeterminate termination status. Countless sloppily written C programs had garbage termination statuses because of this, making it impossible for higher level programs (e.g. scripts) to reliably test for successful execution.
I'm confused. main doesn't take void--it takes two arguments. The f() syntax means that the definition doesn't specify how many arguments the function will be called with, while f(void) means it takes no arguments.
As per the standard, main() can take no argument [ie, main(void)] or 2 arguments [main (int, char asterisk asterisk) or equivalent] or some implementation defined manner. See 5.1.2.2.1 in C2x working draft[0].
Wow, it is painful to see that they still haven't accepted case ranges. They are supported by gcc, clang, and icc. Like so:
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".
I would just be happy with a change that allowed me to not keep repeating the type identifier all the time. Something like:
int foo(int x, y, z, float a, b, c) { ...
instead of
int foo(int x, int y, int z, float a, float b, float c) { ...
Yes, you can pack things like that into a struct sometimes, but not always. From talking to folks who were on the ANSI committee at the time, there was some reason why the first example wouldn't work. Some parsing ambiguity, but I forget the details.
It's distressing to see new languages (like D) adopt this verbose style as if it were some well thought out idea. It wasn't, it was just a consequence of the new declaration style that the ANSI C committee adopted.
varargs functions require at least one non-vararg parameter.
(As int_19h said:) On some architectures, vararg functions have their own distinct ABI, so (...) as a declaration is not compatible with any definition that doesn't also use (...).
There's already the "..." token to signify a variadic function, which is effectively what "takes parameters that you can't list" means, although I believe it's currently defined only for at least one non-variadic argument.
Furthermore, on some architectures, vararg functions have their own distinct ABI, so (...) as a declaration is not compatible with any definition that doesn't also use (...).
The construct would be a pointless throwback to poorer type safety. Every C function call is statically typed and so is a function definition. The declaration of what is being called may tell you nothing about the argument list, but the call expression which uses that identifier will assume a static type for it, based on how it is called. The call will be compiled assuming it has a certain type, which may or may not match what is being called. There is no run time-check; if it's wrong, it's undefined behavior.
You can approximate an argument list using compound literals as long as 0/NULL is an acceptable default value. It's a bit noisy, but it works something like this if I remember right:
result = foo(&(struct foo_args){.arg1 = 4, .arg7 = "2"})
For those who are still wondering the actual reason for the extra instruction after reading all that, it has to do with the calling convention: when calling a variadic function in SysV AMD64, AL holds the number of vector registers used for parameters. I believe the Microsoft x64 one doesn't do that.
> So Clang can potentially save you a single instruction (xorl %eax, %eax) whose encoding is only 1B, per function call to functions declared in the style f(), but only IF the definition is in the same translation unit and doesn’t differ from the declaration, and you happen to be targeting x86_64.
Yeah, it's an overload as others have replied. The difference between C and C++ here, is that you should get a linker error if you try and invoke the undefined overload in C++ (C doesn't allow overloading, nor does it require a forward declaration).
This is how we "deleted" functions, especially otherwise auto generated ones such as a default or copy constructor and assignment operator pre C++11.
I feel like basically any "explanation" of fails to sufficiently explain `f()`.
`void f(){}` is just a special case of the old style of defining functions. Another case of this is `void f(a, b) int a, b; {}`.
Using the old style, functions are defined without "prototypes"; that is, the type of the function does not specify its arguments.
Since changing the meaning of `void f(){}` would have broken backwards compatibility, they added `void f(void){}` as the way of specifying "no arguments" in the new style.
Edit: to further demonstrate, this is a perfectly valid C program:
> void f(a, b) int a, b; {}
> int main(void) { if(0) f("oops"); }
As the type of `f` does not specify its arguments, there is no constraint violation (compilation error), and as the call is never actually performed (`if(0) ..`), the program does not invoke the undefined behaviour that would result in performing the invalid call.
In the conclusion the author says he considers T f() to be prettier than T f(void). I personally prefer the look of T f(void) to T f(); the former is explicit to both the programmer and the compiler that this function is not supposed to take any arguments. If I can cause the compiler to not be helpfully clever when it doesn't need to be, as well as make it clear to my future selves, or any other poor soul condemned to read my code what my actual intention was, I see that as a Good Thing.
> If we change foo2 to a declaration (such as would be the case if it was defined in an external translation unit, and its declaration included via header), then Clang can no longer observe whether foo2 definition differs or not from the declaration.
I tried enabling link time optimization on clang-8, it does see through and eliminate redundant xor instruction in foo2(). gcc fails to do that, however. I inspect the result by calling objdump on generated object code.
T foo() is a deprecated old style from before ANSI C 1989 which declares foo in a way that is mum about how many arguments there are and what their types are.
(void) is actually an ANSI C invention. C++ adopted this for better C compatibility. (Yes, C++ did that once upon a time!) Then some C++ coders started doing silly things like myclass::myclass(void): something that would never be processed with a C compiler.
(void) is ugly; it would be a productive change in C to do away with K&R declarations and make () equivalent to (void) like C++ did some three decades ago.