You've managed to blur things horribly.
void main(hello)
declares main
(incorrectly) as returning nothing and taking a single argument of type int
(implicit int
). You can't call an int
; hence your local variable hides the external function of the same name. The C89 and pre-standard C allowed the 'implicit int
' notation; it is officially not allowed in C99 or C11, though many compilers will continue to allow it unless you ask them for warnings.
You should declare main()
as either:
int main(void)
int main(int argc, char **argv)
Windows does allow void main()
, sadly. C++ does not.
If you use GCC, compile with options like -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration
(preferably with -Werror
). Not all versions of GCC support all those options; use those that your version does support.
Incidentally, by declaring hello
as an argument to main()
, you are hiding or shadowing the external definition of the hello()
function. This is standard C behaviour; a name defined at local scope hides different objects with the same name defined at outer scope levels. You can use the -Wshadow
option to GCC to spot when you run into this as a problem.
Post-Edit
As I already asked, why on earth do you think the startup environment is going to pass a pointer-to-function to your main()
?
The function definition:
void main(void hello(void))
still does not match one of the acceptable patterns.
Further, the startup code won't pass a pointer to function to your main()
; it will basically call your code as if you'd written int main(int argc, char **argv)
(or possibly int main(int argc, char **argv, char **envp)
). You are guaranteed not to get a pointer-to-function passed to your main()
.
So, whatever else happens, you will not be successful. Typically, the value of argc
(and perhaps part of argv
) will be treated as a pointer to function (even though it isn't). All hell will break loose.
Simply define:
int main(void)
and call hello()
directly in the body of main()
. That's about all that makes sense.
For the record, this is what GCC says about the code in the question (as amended):
$ gcc -O3 -g -I/Users/jleffler/inc -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -Wshadow -c hello.c
hello.c:3:6: error: no previous prototype for ‘hello’ [-Werror=missing-prototypes]
void hello(void)
^
hello.c:8:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(void hello (void))
^
hello.c:8:6: error: first argument of ‘main’ should be ‘int’ [-Werror=main]
hello.c:8:6: error: ‘main’ takes only zero or two arguments [-Werror=main]
hello.c: In function ‘main’:
hello.c:8:16: error: declaration of ‘hello’ shadows a global declaration [-Werror=shadow]
void main(void hello (void))
^
hello.c:3:6: error: shadowed declaration is here [-Werror=shadow]
void hello(void)
^
cc1: all warnings being treated as errors
$
Passing pointers to functions — the OpenGL code
You can pass a pointer-to-function as an argument to any function that expects such an argument. However, main()
is one of the functions you can't tinker with (the functions in the Standard C library should be treated as 'cannot be changed' either; ditto the operating system interfaces for the platform(s) you use).
In your OpenGL example code, it is perfectly legitimate to pass a function pointer like display
or reshape
to the glutDisplayFunc()
and glutReshapeFunc()
functions because they are designed to accept pointers to functions. Had you written your initial offering as:
#include <stdio.h>
static void hello(void)
{
printf("hello there\n");
}
static void invoke(void (*function)(void))
{
printf("-->> %s:\n", __func__);
function(); // Or (*function)();
printf("<<-- %s\n", __func__);
}
int main(void)
{
int y = 100;
printf("%i\n", y);
if (y == 100)
invoke(hello);
return 0;
}
there would have been no outcry from anyone — compiler or human. This is clean (C99 or C11) code that helps in understanding pointers to functions. If you write void invoke(void function(void))
without the explicit pointer, the compiler automatically converts the type to 'pointer to function taking no arguments and returning no value — aka void (*function)(void)
. So, you can write that if you prefer, though I prefer the explicit pointer notation, not least because inside a function, or as a global variable, you must use the explicit pointer notation, so using that with function arguments is consistent. Inside a function, writing:
void function(void);
declares a function, not a pointer to function variable; that must be written:
void (*function)(void) = hello; // Note no parentheses on hello!
Similarly at with variables at file scope. So, using the void (*function)(void)
notation in function argument lists (in prototypes and definitions) is consistent with the rest of the language and is therefore the better notation to use.