Pregunta

me encontré con este problema mientras que el desarrollo en Objective-C para iOS, pero esto debe aplicarse a cualquier código C / C ++ / Objective-C utilizando el enlazador Mac OS X / IOS. La solución está cubierto por otra pregunta , pero estoy interesado en ¿Por qué .

Vamos a decir que estoy usando un enlace a una biblioteca que define una constante. En un archivo de cabecera hay una declaración como esta:

extern char * const BrandNewIdentifier;

Quiero compilar mi aplicación y ejecutarlo en un sistema con una versión anterior de la biblioteca, donde esa constante no tiene una definición, por lo que para estar seguro que no considere que se ha definido.

Ahora, si hay una función que sólo se define en la versión más reciente de la biblioteca, yo puedo hacer esto:

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

En lugar de contener la dirección del código de función, evalúa BrandNewFunc a NULL. Me gustaría pensar que la constante se comportaría de la misma manera, pero si intento el mismo patrón, las matrices de aplicaciones al realizar una comprobación (tiros EXC_BAD_ACCESS en IOS). Específicamente:

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

Lo que funciona en su lugar es el control de la dirección del identificador:

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

Me puede ver la lógica: BrandNewIdentifier no tiene ningún valor, por lo que el acceso debería fallar. Pero entonces ¿por qué hace ese trabajo de sintaxis en el caso de BrandNewFunc? ¿No debería ser requerido para comprobar su dirección también? ¿O es realmente consistente, y hay algo que he pasado por alto?

¿Fue útil?

Solución

La parte relevante de la norma C es la sección 6.3.2.1 "Lvalues, arrays, y designadores de función". Esto es lo que dice acerca de las funciones:

  

A función designador es una expresión que tiene el tipo de función. Excepto cuando es el operando del operador sizeof 65 o el operador & unario, un designador de función con el tipo '' función que devuelve type '' se convierte en una expresión que tiene escribir '' puntero a una función que devuelve type ''.

     

[nota 65] Debido a esta conversión no se produce, el operando del operador sizeof sigue siendo un indicador de función y viola la restricción en 6.5.3.4 [ed: la restricción en 6.5.3.4 dice que es posible que no se aplique a un sizeof función designador -. que es un error semántico]

Un identificador que nombra a una función es el tipo más simple de "expresión que tiene el tipo de función". Lo que esto significa es que si foo ha sido declarada como una función, los evalúa identificador foo como un puntero a esa función, excepto cuando es el operando de & (en cuyo caso los evalúa la expresión &foo más grandes como un puntero a esa función) o el operando de sizeof (en cuyo caso la expresión mayor, sizeof(foo), provoca un error de compilación).

tl, dr: Cuando foo es una función, foo y &foo son equivalentes por definición. Esta es una regla especial para funciones. No es del todo a diferencia de la regla especial para las matrices, que también "descomposición" de punteros en muchos contextos (la regla es un párrafo a partir de la que he citado).

Aparte: Sí, esto significa que el operador de la función de llamada siempre opera en una función de puntero a. Cuando pfunc es una variable de puntero a función, (*pfunc)() se procesa como si se lee (&(*pfunc))() ... o simplemente pfunc().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top