Pourquoi std:: cout convertit-il les pointeurs volatiles en bool?
si vous essayez de pointer vers un type volatile, même un pointeur de char volatile où vous vous attendez normalement à ce que cout imprime la chaîne, vous obtiendrez simplement '1' (en supposant que le pointeur n'est pas nul je pense). Je suppose que l'opérateur de flux de sortie< < est template spécialisé pour les pointeurs volatiles, mais ma question est, pourquoi? À quoi sert le cas qui motive ce comportement?
exemple de code:
#include <iostream>
#include <cstring>
int main()
{
char x[500];
std::strcpy(x, "Hello world");
int y;
int *z = &y;
std::cout << x << std::endl;
std::cout << (char volatile*)x << std::endl;
std::cout << z << std::endl;
std::cout << (int volatile*)z << std::endl;
return 0;
}
Sortie:
Hello world
1
0x8046b6c
1
4 réponses
ostream::operator<<
a les surcharges suivantes, entre autres:
ostream& operator<< (bool val );
ostream& operator<< (const void* val );
quand vous passez dans un pointeur volatile, la deuxième surcharge ne peut pas s'appliquer parce que les pointeurs volatiles ne peuvent pas être convertis en non-volatiles sans un moulage explicite. Cependant, un pointeur peut-être convertie en booléen, donc la première surcharge est choisie, et le résultat que vous voyez est 1 ou 0.
je pense que la raison est que les pointeurs volatiles ne peuvent pas être convertis implicitement en void *. Cela se trouve à L'Annexe C de la norme, et la raison d'être est la sécurité de type.
Changement: Uniquement des pointeurs à des non-const et les objets non volatils peuvent être implicitement converti à void* Justification: Cette améliore la sécurité du type.
donc au lieu de la conversion à void * (qui s'imprimerait en hex), vous obtenez la conversion "par défaut" en bool.
Pas de réponse
ce n'est qu'un problème de formulation de la question et des réponses. Le problème se pose en raison de l'impossibilité de convertir pointeurs vers volatile objets dans le vide pointeurs, pas pointeurs volatils.
la différence, qui est assez importante, est ce que l'élément de mémoire est celui qui est volatile. Dans la question, le pointeur n'est pas volatile (il peut être mis en cache, et il n'a pas à être vidées à la mémoire quand elle est changée), mais plutôt la mémoire pointue:
int volatile * p = f();
p++; // this does not affect the perceived state of the c++ memory model
++p;
*p = 5; // this changes the perceived state
la raison pour laquelle il est important est qu'avec un pointeur vers la mémoire volatile, le pointeur lui-même est celui qui a un traitement spécial.
void foo( int * );
int * volatile p = f(); // 1
foo(p); // 2
int volatile * q = f();
//foo(q); // error, cannot convert pointer to volatile to pointer to non-volatile
*q = 5; // 3
q = 0; // 4
dans le code ci-dessus, les opérations marquées 1 et 2 font tout le chemin vers la mémoire. La tâche dans [1] doit être mise en mémoire. Même si la valeur de p
est dans un registre, il sera chargé de mémoire à [2]. L'opération marquée [3] modifie la valeur pointée par q
qui est volatile
et fera tout le chemin jusqu'à la mémoire principale, alors que l'opération [4] n'affecte que le pointeur, qui n'est pas volatile
elle-même, et en tant que telle ne fait pas partie de l'état de perception du modèle de mémoire c++ et peut être exécutée dans des registres (notez qu'un compilateur peut optimiser à distance q
et effectuer les opérations dans un registre, tandis que p
ne peut pas être optimisé.
je pense que le problème n'est pas une surcharge explicite pour les pointeurs vers les types volatils, mais un manque de surcharge pour les pointeurs vers les types volatils. Le compilateur ne peut pas supprimer implicitement le qualificatif volatile des pointeurs de sorte qu'il vérifie les surcharges disponibles, choisit la version bool de l'opérateur<< et convertit le pointeur-to-volatile en bool.