The first expression is perfectly legal in C, as the void *
pointer type is assignment and parameter passing compatible with any other pointer type, and you can run into trouble, if pointers are different size than integers. It's not good programming style, and there's apparently no reason to assign to a function pointer the integer literal 9
. I cannot guess what are you doing so for.
Despite of that, there are some few (well, very few) cases in history that that thing has been done (e.g. to give the special values SIG_DFL
and SIG_IGN
to the signal(2)
system call, one can assume nobody will ever use those values to call the function dereferenced by the pointer, indeed, you can use some integers, different than zero, in the page zero virtual addresses of a process, to avoid dereferencing the pointers (so you cannot call the functions, or you'll get a segmentation violation immediately), while using different than zero values to assume several values apart of the NULL
pointer itself)
But the second expression is not legal. It's not valid for an expression to start with a type identifier, so the subexpression to the right of the =
sign is invalid. To do a correct assignment, with a valid cast, you had to write:
void (*ptr)(void) = (void (*)(void)) 0x9; /* wth to write so many zeros? */
(enclosing the whole type mark in parenthesis) then, you can call the function as:
(*ptr)();
or simply as:
ptr();
Just writing
void(*ptr)(void) = 9;
is also legal, while the integer to pointer conversion is signalled by almost every compiler with a warning. You'll get an executable from there.
If the integer is 0
, then the compiler will shut up, as 0
is converted automatically to the NULL
pointer.
EDIT
To illustrate the simple use I mentioned above in the first paragraph, from the file <sys/signal.h>
of FreeBSD 12.0:
File /usr/include/sys/signal.h
139 #define SIG_DFL ((__sighandler_t *)0)
140 #define SIG_IGN ((__sighandler_t *)1)
141 #define SIG_ERR ((__sighandler_t *)-1)
142 /* #define SIG_CATCH ((__sighandler_t *)2) See signalvar.h */
143 #define SIG_HOLD ((__sighandler_t *)3)
all those definitions are precisely of the type mentioned in the question, an integer value cast to a pointer to function, in order to permit special values to represent non executable/non callback values. The type __sighandler_t
is defined as:
161 typedef void __sighandler_t(int);
below.
From CLANG:
$ cc -std=c17 -c pru.c
$ cat pru.c
void (*ptr)(void) = (void *)0x9;
you get even no warning at all.
Without the cast:
$ cc -std=c11 pru.c
pru.c:1:8: warning: incompatible integer to pointer conversion
initializing 'void (*)(void)' with an expression of type 'int'
[-Wint-conversion]
void (*ptr)(void) = 0x9;
^ ~~~
1 warning generated.
(Only a warning, not an error)
With a zero literal:
$ cc -std=c11 -c pru.c
$ cat pru.c
void (*ptr)(void) = 0x0;
even no warning at all.