A function name without parentheses doesn't return a value - it evaluates to the address of the function (i. e. it is a function pointer of type size_t (*)(const char *, ...)). Essentially, this is the address where the CPU will jump among the instructions whenever it encounters a call to printf().
By the way, if I recall correctly, assigning to a function's name is undefined behavior, so is printing a pointer using the %d format specifier - you should use
printf("%p", (void *)printf);
Also, you can declare function pointers, assign them the address of another function and call them just fine:
size_t (*my_printf)(const char *, ...) = printf;
my_printf("This actually called printf!\n");
printf("my_printf: %p\n", (void *)my_printf);
printf("original printf: %p\n", (void *)printf);
The last two statements print the same address.
Edit: Strictly speaking, even the above "solution" is nonstandard as the Standard doesn't guarantee that function pointers can be cast to data pointer types. That means basically that there's no way for print the address of a function, however, on most systems, casting to void * apparently works.
int, but argument 2 has typeint (*)(const char * __restrict__)". i.e.printfis the pointer that points toprintf ().