Issue
This is the construct in question:
int main (void)
{
int a = 5;
(func)(a);
return 0;
}
Compiled with GNU GCC C99 the following will happen:
- If
func
was defined as a function beforemain()
the function will be executed. - If
func
was not defined as a function beforemain
the compiler issues "func undeclared" error
However, if I remove the braces around func
the function will be implicitly declared so even if it is defined in another translation unit, it will execute, which is the behavior I would always expect.
A recursive-descent parser identifies a function call expression (also according to the standard) by the presence of (arguments)
which is why code like 3(a);
would issue an error: "called object is not a function or function pointer". And just like other similar operations such as the suffix increment, what comes before (arguments)
is expected to be a subexpression - in this case the constraint demands an operand that is a function or a function pointer. With every other operation you can freely add as many brackets as you like: ((a))++
and that wouldn't change a thing, however with function calls it does not look quite like that.
Why would that code behave differently, is it a language feature that I didn't know of, or a result from some carefully crafted parsing design choice?
Solution
This is because of how implicit declarations were defined in C89. Only a bare identifier qualifies as an implicit declaration.
This is spelled out in section 3.3.2.2 of the C89 standard:
If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration
extern int identifier();
appeared.
Since in this case:
(func)(a);
The expression preceding the parenthesized arguments is not just an identifier, it does not qualify as an implicit declaration.
As for why gcc still seems to allow this even in C99 and later mode with -pedantic
, I'd chalk that up to either an extension or a bug.
Answered By - dbush Answer Checked By - Willingham (WPSolving Volunteer)