A. K. schrieb:
> Das wird ziemlich konsequent, wenn man () als Dereferenzierung eines
> Funktionszeigers betrachtet.
>
> Die Versionen mit * und & sind eigentlich nur Konzessionen an jene
> Leute, die mit dieser inneren Logik auf Kriegsfuss stehen.
Ich hab mir mal die Mühe gemacht, aus dem Standard rauszusuchen, warum
das überhaupt funktioniert, bzw. wie die Definitionen da laufen
Der Name einer Funktion ist im C Standard ein 'Function Designator', der
bei Bedarf automatisch in einem 'Pointer to function' konvertiert wird.
(6.3.2 - 4)
Weiters heisst es
1 | 6.5.2.2 Function calls
|
2 | Constraints
|
3 | 1 The expression that denotes the called function (80) shall
|
4 | have type pointer to function
|
Fussnote 80 besagt
1 | 80) Most often, this is the result of converting an identifier that
|
2 | is a function designator
|
D.h. das man überhaupt
1 | void foo( void )
|
2 | {
|
3 | ..
|
4 | }
|
5 | ...
|
6 | foo();
|
schreiben kann, liegt daran, dass der Function Designator 'foo'
automatisch in einen Function Pointer umgewandelt wird, über den dann
die Funktion aufgerufen wird.
Wenn man also schreibt
1 | void (*ptr)( void ) = foo;
|
2 | ...
|
3 | ptr();
|
dann wird die Funktion aufgerufen, weil ptr schon den eigentlich
korrekten Datentyp 'Pointer to function' hat.
Schreibt man hingegen
dann mündet die Dereferenzierung des Pointers laut 6.5.3.2 - 4 wieder in
einem Function Designator, der dann konzeptionell wieder in einen
Function Pointer implizit umgewandelt wird um die Funktion aufzurufen.