Question

je suis tombé sur ce problème tout en développant en Objective-C pour iOS, mais cela devrait s'appliquer à tout C / C ++ / code Objective-C en utilisant Mac OS X / éditeur de liens iOS. La solution est couvert par autre question , mais je suis intéressé par pourquoi .

Le mot Let J'utilise un lien vers une bibliothèque qui définit une constante. Dans un fichier d'en-tête il y a une déclaration comme ceci:

extern char * const BrandNewIdentifier;

Je veux compiler mon application et l'exécuter sur un système avec une version antérieure de la bibliothèque, où cette constante n'a pas de définition, donc pour être sûr que je ne suppose pas qu'il a été défini.

Maintenant, s'il y a une fonction qui est définie que dans la version la plus récente de la bibliothèque, je peux faire ceci:

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

Au lieu de contenir l'adresse du code de fonction, évalue de BrandNewFunc à NULL. Je pense que la constante se comporterait de la même façon, mais si je tente le même modèle, les matrices d'application lors d'une vérification (lancers francs EXC_BAD_ACCESS sur iOS). Plus précisément:

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

Ce qui fonctionne au lieu vérifie l'adresse de l'identifiant:

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

Je peux voir la logique: BrandNewIdentifier n'a pas de valeur, afin d'y accéder devrait échouer. Mais alors pourquoi est-ce que le travail de syntaxe dans le cas de BrandNewFunc? Je ne devrais pas être tenu de vérifier son adresse aussi? Ou est-il réellement cohérent, et il y a quelque chose que j'ai négligé?

Était-ce utile?

La solution

La partie pertinente de la norme C est la section 6.3.2.1 « Lvalues, les tableaux et les désignateurs de fonction ». Voici ce qu'il dit sur les fonctions:

  

désignateur de fonction est une expression qui a le type de fonction. Sauf quand il est l'opérande de l'opérateur sizeof 65 ou l'opérateur unaire &, un identifiant de fonction de type « » fonction renvoyant type « » est converti en une expression qui a type '' pointeur de retourner la fonction type .

     

[note 65] Parce que cette conversion ne se produit pas, l'opérande de l'opérateur sizeof reste un désignateur de fonction et viole la contrainte en 6.5.3.4 [ndlr: la contrainte 6.5.3.4 dit que vous ne pouvez pas demander à un sizeof désignateur fonction -. il est une erreur sémantique]

Un identifiant qui nomme une fonction est la plus simple sorte de « expression qui a le type de fonction ». Donc, cela signifie, si foo a été déclarée en fonction, les évalue de foo identifiant comme un pointeur vers cette fonction, à l'exception quand il est l'opérande de & (auquel cas l'expression plus grandes &foo evalue comme un pointeur sur cette fonction) ou l'opérande de sizeof (auquel cas la plus grande expression, sizeof(foo), provoque une erreur de compilation).

tl, dr: Lorsque foo est une fonction, foo et &foo sont équivalents par définition. Ceci est une règle spéciale pour les fonctions. Il est pas tout à fait contrairement à la règle spéciale pour les tableaux, qui a également « désintégration » des pointeurs dans de nombreux contextes (cette règle est un paragraphe vers le haut de celui que je citais).

En plus: Oui, cela signifie que l'opérateur d'appel de fonction toujours fonctionne sur un pointeur à la fonction. Lorsque pfunc est une variable pointeur à la fonction, (*pfunc)() est traitée comme si elle lisait (&(*pfunc))() ... ou tout simplement pfunc().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top