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
où 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;
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).
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.
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.
/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.