web-dev-qa-db-fra.com

Signification de int (*) (int *) = 5 (ou toute valeur entière)

Je ne peux pas comprendre cela:

int main() {
    int (*) (int *) = 5;
    return 0;
}

L'affectation ci-dessus se compile avec g ++ c ++ 11. Je sais que int (*) (int *) est un pointeur vers une fonction qui accepte un (int *) Comme argument et renvoie un entier, mais je ne comprends pas comment vous pourriez l'assimiler à 5. Au début, je pensais que est une fonction qui renvoie constamment 5 (de mon récent apprentissage en F #, probablement haha), alors j'ai pensé, brièvement, que le pointeur de la fonction pointe vers l'emplacement mémoire 5, mais cela ne fonctionne pas, clairement, et les valeurs hexadécimales non plus.

Pensant que cela pourrait être parce que la fonction renvoie un int et que l'attribution d'un int est ok (en quelque sorte), j'ai également essayé ceci:

int * (*) (int *) = my_ptr

my_ptr est de type int *, du même type que ce deuxième pointeur de fonction, comme dans le premier cas avec le type int. Cela ne compile pas. Assigner 5, ou n'importe quelle valeur int, au lieu de my_ptr, Ne compile pas non plus pour ce pointeur de fonction.

Alors, que signifie la mission?

mise à jour 1

Nous avons la confirmation qu'il s'agit d'un bug, comme indiqué dans la meilleure réponse. Cependant, on ne sait toujours pas ce qui se passe réellement à la valeur que vous affectez au pointeur de fonction, ni ce qui se passe avec l'affectation. Toute (bonne) explication à ce sujet serait très appréciée! Veuillez vous référer aux modifications ci-dessous pour plus de clarté sur le problème.

Modifier 1

J'utilise gcc version 4.8.2 (dans Ubuntu 4.8.2)

Modifier 2

En fait, l'assimiler à tout fonctionne sur mon compilateur. Même l'assimiler à une variable std :: string, ou à un nom de fonction qui renvoie un double, fonctionne.

Modifier 2.1

Fait intéressant, ce qui en fait un pointeur de fonction vers toute fonction qui renvoie un type de données qui n'est pas un pointeur, permettra de le compiler, comme

std::string (*) () = 5.6;

Mais dès que le pointeur de fonction est vers une fonction qui renvoie un pointeur, il ne compile pas, comme avec

some_data_type ** (*) () = any_value;
87
Konrad Kapp

C'est un bug dans g ++.

 int (*) (int *) 

est un nom de type.

En C++, vous ne pouvez pas avoir de déclaration avec un nom de type sans identifiant.

Donc, cela compile avec g ++.

 int (*) (int *) = 5;

et cela compile aussi:

 int (*) (int *);

mais ce sont deux déclarations invalides.

[~ # ~] éditez [~ # ~] :

T.C. mentionne dans les commentaires bug bugzilla 6068 avec un cas de test similaire mais il n'a pas encore été approuvé. Le bug est confirmé dans bugzilla.

EDIT2 :

Lorsque les deux déclarations ci-dessus se trouvent dans la portée du fichier, g ++ émet correctement un diagnostic (il ne parvient pas à lancer le diagnostic dans la portée du bloc).

EDIT3 :

J'ai vérifié et je peux reproduire le problème sur la dernière version de g ++ version 4 (4.9.2), la dernière version préliminaire 5 (5.0.1 20150412) et la dernière version expérimentale 6 (6.0.0 20150412).

59
ouah

Ce n'est pas du C++ valide. Souvenez-vous que parce que votre compilateur particulier arrive à le compiler, il ne le rend pas valide. Les compilateurs, comme tous les logiciels complexes, ont parfois des bogues et cela semble en être un.

Par contre clang++ Se plaint:

funnycast.cpp:3:11: error: expected expression
    int (*) (int *) = 5;
          ^
funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction
    int (*) (int *) = 5;
             ~~~ ^
funnycast.cpp:3:19: error: expected expression
    int (*) (int *) = 5;
                  ^
3 errors generated.

Il s'agit du comportement attendu car la ligne incriminée n'est pas C++ valide. Il s'agit d'une affectation (en raison du =) mais ne contient aucun identifiant.

27
Edward

Comme d'autres réponses l'ont souligné, c'est un bug qui

int (*) (int *) = 5;

compile. Une approximation raisonnable de cette déclaration qui devrait avoir un sens est la suivante:

int (*proc)(int*) = (int (*)(int*))(5);

Maintenant proc est un pointeur vers une fonction qui attend l'adresse 5 pour être l'adresse de base d'une fonction qui prend un int* et renvoie un int.

Sur certains microcontrôleurs/microprocesseurs 5 peut être une adresse de code valide et il peut être possible de localiser une telle fonction là-bas.

Sur la plupart des ordinateurs à usage général, la première page de mémoire (adresses 0-1023 pour les pages 4K) sont délibérément invalides (non mappés) afin d'attraper les accès au pointeur null.

Ainsi, alors que le comportement dépend de la plate-forme, on peut raisonnablement s'attendre à ce qu'une erreur de page se produise lorsque *proc est invoqué (par exemple, (*proc)(&v)). Avant l'heure à laquelle *proc est invoqué, rien d'inhabituel ne se produit.

Sauf si vous écrivez un éditeur de liens dynamique, vous ne devriez certainement pas calculer numériquement des adresses et les affecter à des variables pointeur-fonction.

9
Atsby
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp

Cette ligne de commande génère de nombreux fichiers intermédiaires. Le premier d'entre eux, so.cpp.170r.expand, dit:

...
int main() ()
{
  int D.2229;
  int _1;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  _1 = 0;
;;    succ:       3

;;   basic block 3, loop depth 0
;;    pred:       2
<L0>:
  return _1;
;;    succ:       EXIT

}
...

Cela ne répond toujours pas à ce qui se passe exactement, mais ce devrait être un pas dans la bonne direction.

2
Roland Illig