Question

I ran into this problem while developing in Objective-C for iOS, but this should apply to any C/C++/Objective-C code using the Mac OS X/iOS linker. The solution is covered by another question, but I'm interested in the why.

Let's say I'm using a linking to a library which defines a constant. In a header file there is a declaration like this:

extern char * const BrandNewIdentifier;

I want to compile my application and run it on a system with an earlier version of the library, where that constant has no definition, so to be safe I don't assume it has been defined.

Now, if there's a function that is only defined in the most recent version of the library, I can do this:

if (BrandNewFunc) {
    BrandNewFunc("foobar", 42);
} else {
    printf("Your system does not support some thing.");
}

Instead of containing the address of function code, BrandNewFunc evaluates to NULL. I would think that the constant would behave the same way, but if I try the same pattern, the app dies while performing a check (throws EXC_BAD_ACCESS on iOS). Specifically:

if (BrandNewIdentifier) ... // blows up here

What works instead is checking the address of the identifier:

if (&BrandNewIdentifier) {
    printf("You got it!");
}

I can see the logic: BrandNewIdentifier has no value, so accessing it should fail. But then why does that syntax work in the case of BrandNewFunc? Shouldn't I be required to check its address also? Or is it actually consistent, and there is something I've overlooked?

Was it helpful?

Solution

The relevant part of the C standard is section 6.3.2.1 "Lvalues, arrays, and function designators". Here's what it says about functions:

A function designator is an expression that has function type. Except when it is the operand of the sizeof operator65 or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.

[footnote 65] Because this conversion does not occur, the operand of the sizeof operator remains a function designator and violates the constraint in 6.5.3.4 [ed: the constraint in 6.5.3.4 says that you may not apply sizeof to a function designator - it's a semantic error].

An identifier that names a function is the simplest sort of "expression that has function type". So what this means is, if foo has been declared as a function, the identifier foo evaluates as a pointer to that function, except when it's the operand of & (in which case the larger expression &foo evaluates as a pointer to that function) or the operand of sizeof (in which case the larger expression, sizeof(foo), provokes a compile error).

tl,dr: When foo is a function, foo and &foo are equivalent by definition. This is a special rule for functions. It's not entirely unlike the special rule for arrays, which also "decay" to pointers in many contexts (that rule is one paragraph up from the one I quoted).

Aside: Yes, this means that the function-call operator always operates on a pointer-to-function. When pfunc is a pointer-to-function variable, (*pfunc)() is processed as if it read (&(*pfunc))() ... or just pfunc().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top