Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cet article décrit l’utilisation de la syntaxe d’expression C++ avec les outils de débogage Windows.
Le débogueur accepte deux types d’expressions numériques différents : les expressions C++ et les expressions MICROSOFT Macro Assembleur (MASM). Chacune de ces expressions suit ses propres règles de syntaxe pour l’entrée et la sortie.
Pour plus d’informations sur l’utilisation de chaque type de syntaxe, consultez Évaluation des expressions et la commande ? évaluer l'expression.
L’analyseur d’expression C++ prend en charge toutes les formes de syntaxe d’expression C++. La syntaxe inclut tous les types de données, notamment les pointeurs, les nombres à virgule flottante et les tableaux, ainsi que tous les opérateurs unaires et binaires C++.
Les fenêtres Watch et Locals du débogueur utilisent toujours l’évaluateur d’expression C++.
Dans l’exemple suivant, la commande ?? evaluate C++ expression affiche la valeur du registre pointeur d'instruction.
0:000> ?? @eip
unsigned int 0x771e1a02
Nous pouvons utiliser la fonction C++ sizeof pour déterminer la taille des structures.
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Définir l’évaluateur d’expression sur C++
Utilisez .expr choisir l’évaluateur d’expression pour afficher l’évaluateur d’expression par défaut et le remplacer par C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
Une fois que l’évaluateur d’expression par défaut a été modifié, la commande ? évaluer l'expression peut être utilisée pour afficher des expressions C++. L’exemple suivant affiche la valeur du registre du pointeur d’instruction.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Pour en savoir plus sur la référence du @eip registre, consultez la syntaxe du registre.
Dans cet exemple, la valeur hexadécimal de 0xD est ajoutée au registre eip.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Registres et pseudo-registres dans des expressions C++
Vous pouvez utiliser des registres et des pseudo-registres dans des expressions C++. Le signe @ doit être ajouté avant le registre ou le pseudo-registre.
L’évaluateur d’expression effectue automatiquement le cast approprié. Les registres réels et les pseudo-registres de valeur entière sont convertis en ULONG64. Toutes les adresses sont castées en PUCHAR, $thread est castée en ETHREAD*, $proc est castée en EPROCESS*, $teb est castée en TEB*, et $peb est castée en PEB*.
Cet exemple montre comment afficher le TEB.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
Vous ne pouvez pas modifier un registre ou un pseudo-registre par un opérateur d’affectation ou d’effet secondaire. Vous devez utiliser la commande r registers pour modifier ces valeurs.
L’exemple suivant définit le pseudo-registre sur une valeur de 5, puis l’affiche.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Pour plus d’informations sur les registres et les pseudo-registres, consultez la syntaxe Register et la syntaxe pseudo-registre.
Nombres dans les expressions C++
Les nombres dans les expressions C++ sont interprétés comme des nombres décimaux, sauf si vous les spécifiez d’une autre manière. Pour spécifier un entier hexadécimal, ajoutez 0x avant le nombre. Pour spécifier un entier octal, ajoutez 0 (zéro) avant le nombre.
Le débogueur par défaut radix n’affecte pas la façon dont vous entrez des expressions C++. Vous ne pouvez pas entrer directement un nombre binaire, sauf en imbrication d’une expression MASM dans l’expression C++.
Vous pouvez entrer une valeur hexadécimale 64 bits au format xxxxxxxx’xxxxxxxx. Vous pouvez également omettre l’accent grave ('). Les deux formats produisent la même valeur.
Vous pouvez utiliser les suffixes L, U et I64 avec des valeurs entières. La taille réelle du nombre créé dépend du suffixe et du nombre que vous entrez. Pour plus d’informations sur cette interprétation, consultez une référence de langage C++.
La sortie de l’évaluateur d’expression C++ conserve le type de données spécifié par les règles d’expression C++. Toutefois, si vous utilisez cette expression comme argument pour une commande, un cast est toujours effectué. Par exemple, vous n’avez pas besoin de convertir des valeurs entières en pointeurs lorsqu’elles sont utilisées comme adresses dans les arguments de commande. Si la valeur de l’expression ne peut pas être convertie validement en entier ou en pointeur, une erreur de syntaxe se produit.
Vous pouvez utiliser le 0n préfixe (décimal) pour une sortie, mais vous ne pouvez pas l’utiliser pour l’entrée d’expression C++.
Caractères et chaînes dans les expressions C++
Vous pouvez entrer un caractère en l’entourant de guillemets simples ('). Les caractères d’échappement C++ standard sont autorisés.
Vous pouvez entrer des littéraux de chaîne en les entourant de guillemets doubles ("). Vous pouvez utiliser \" comme séquence d’échappement dans une telle chaîne. Toutefois, les chaînes n’ont aucune signification pour l’évaluateur d’expression.
Symboles dans les expressions C++
Dans une expression C++, chaque symbole est interprété en fonction de son type. Selon ce que le symbole fait référence, il peut être interprété comme un entier, une structure de données, un pointeur de fonction ou tout autre type de données. Une erreur de syntaxe se produit si vous utilisez un symbole qui ne correspond pas à un type de données C++, tel qu’un nom de module non modifié, dans une expression C++.
Vous pouvez utiliser un accent grave (') ou une apostrophe (') dans un nom de symbole uniquement si vous ajoutez un nom de module et un point d’exclamation avant le nom du symbole. Lorsque vous ajoutez les délimiteurs < et > après un nom de modèle, vous pouvez ajouter des espaces entre ces délimiteurs.
Si le symbole peut être ambigu, vous pouvez ajouter un nom de module et un point d’exclamation ( !) ou uniquement un point d’exclamation avant le symbole. Pour spécifier qu’un symbole est destiné à être local, omettez le nom du module et incluez un signe dollar et un point d’exclamation ($ !) avant le nom du symbole. Pour plus d’informations sur la reconnaissance des symboles, consultez la syntaxe des symboles et la correspondance de symboles.
Structures dans les expressions C++
L’évaluateur d’expression C++ convertit les pseudo-registres en leurs types appropriés. Par exemple, $teb est converti en tant que TEB*.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
L’exemple suivant affiche l’ID de processus dans la structure TEB montrant l’utilisation d’un pointeur vers un membre de la structure référencée.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Opérateurs dans les expressions C++
Vous pouvez utiliser des parenthèses pour remplacer les règles de précédence.
Si vous placez une partie d’une expression C++ entre parenthèses et ajoutez deux signes at ( @@) avant l’expression, l’expression est interprétée en fonction des règles d’expression MASM. Vous ne pouvez pas ajouter d’espace entre les deux signes et la parenthèse ouvrante. La valeur finale de cette expression est transmise à l’évaluateur d’expression C++ en tant que valeur ULONG64. Vous pouvez également spécifier l’évaluateur d’expression à l’aide @@c++( ... ) ou @@masm( ... ).
Les types de données sont indiqués comme d’habitude dans le langage C++. Les symboles qui indiquent des tableaux ([ ]), les membres du pointeur (->), les membres UDT (.) et les membres des classes ( ::) sont tous reconnus. Tous les opérateurs arithmétiques sont pris en charge, y compris les opérateurs d’affectation et d’effet secondaire. Toutefois, vous ne pouvez pas utiliser les newopérateurs , deleteet throw vous ne pouvez pas appeler réellement une fonction.
L’arithmétique des pointeurs est prise en charge et les décalages sont correctement ajustés. Notez que vous ne pouvez pas ajouter de décalage à un pointeur de fonction. Si vous devez ajouter un décalage à un pointeur de fonction, convertissez d’abord le décalage en pointeur de caractère.
Comme dans C++, si vous utilisez des opérateurs avec des types de données non valides, une erreur de syntaxe se produit. L’analyseur d’expressions C++ du débogueur utilise des règles légèrement plus souples que la plupart des compilateurs C++, mais toutes les règles principales sont appliquées. Par exemple, vous ne pouvez pas décaler une valeur non entière.
Vous pouvez utiliser les opérateurs suivants. Les opérateurs de chaque cellule sont prioritaires sur les opérateurs dans les cellules inférieures. Les opérateurs de la même cellule sont de la même priorité et sont analysés de gauche à droite.
Comme avec C++, l’évaluation d’expression se termine lorsque sa valeur est connue. Cette fin vous permet d’utiliser efficacement des expressions telles que ?? myPtr && *myPtr.
Référence et conversion de type
| Opérateur | Sens |
|---|---|
| Expression // Commentaire | Ignorer tout le texte suivant |
| Classe :: Membre | Membre de la classe |
| Classe ::~Membre | Membre de la classe (destructeur) |
| :: Nom | Mondial |
| Structure . Champ | Champ dans une structure |
| Pointeur ->Field | Champ dans la structure référencée |
| Nom [entier] | Indice de tableau |
| LValue ++ | Incrément après l’évaluation |
| LValue -- | Décrémentation (après évaluation) |
| dynamic_cast<type>(Value) | Typecast (toujours effectué) |
| < static_casttype>(Valeur) | Typecast (toujours effectué) |
| reinterpret_cast<type>(Valeur) | Typecast (toujours effectué) |
| < const_casttype>(Valeur) | Typecast (toujours effectué) |
Opérations sur les valeurs
| Opérateur | Sens |
|---|---|
| (type) Valeur | Typecast (toujours effectué) |
| sizeofvalue | Taille de l’expression |
| sizeof( type ) | Taille du type de données |
| ++ LValue | Incrémentation (avant l'évaluation) |
| -- LValue | Décrémentation (avant l’évaluation) |
| ~ Valeur | Complément de bit |
| ! Valeur | Non (Booléen) |
| Valeur | Unaire moins |
| + Valeur | Plus unaire |
| & LValue | Adresse du type de données |
| Valeur | Déréférencement |
| Structure . pointeur | Pointeur vers le membre de la structure |
| Pointeur -> * Pointeur | Pointeur vers le membre de la structure référencée |
Arithmétique
| Opérateur | Sens |
|---|---|
| Valeur | Multiplication |
| Valeur / Valeur | Division |
| Valeur % Valeur | Modulus |
| Valeur + Valeur | Ajout |
| Valeur - Valeur | Soustraction |
| Valeur<<Valeur | Décalage à gauche au niveau du bit |
| Valeur>>Valeur | Décalage au niveau du bit vers la droite |
| Valeur<Valeur | Moins que (comparaison) |
| Valeur<= Valeur | Inférieur ou égal (comparaison) |
| Valeur>Valeur | Supérieur à (comparaison) |
| Valeur>= Valeur | Supérieur ou égal à (comparaison) |
| Valeur == Valeur | Égal (comparaison) |
| Valeur != Valeur | Non égal (comparaison) |
| Valeur & Valeur | AND au niveau du bit |
| Valeur ^ Valeur | XOR au niveau du bit (OR exclusif) |
| Valeur | Valeur | OR au niveau du bit |
| Valeur && Valeur | ET logique |
| Valeur || Valeur | OU logique |
Les exemples suivants supposent que les pseudo-registres sont définis comme indiqué.
0:000> r $t0 = 0
0:000> r $t1 = 1
0:000> r $t2 = 2
0:000> ?? @$t1 + @$t2
unsigned int64 3
0:000> ?? @$t2/@$t1
unsigned int64 2
0:000> ?? @$t2|@$t1
unsigned int64 3
Tâche
| Opérateur | Sens |
|---|---|
| LValue = Valeur | Attribuer |
| LValue *= Valeur | Multiplier et affecter |
| LValue /= Valeur | Diviser et affecter |
| LValue %= Valeur | Modulo et affectation |
| LValue += Valeur | Ajouter et affecter |
| LValue -= Valeur | Soustraire puis affecter |
| LValue<<= Valeur | Décalage à gauche et affectation |
| LValue>>= Valeur | Décalage droit et affectation |
| LValue &= Value | AND et assigner |
| LValue |= Valeur | OR et assigner |
| LValue ^= Valeur | XOR et assigner |
Évaluation
| Opérateur | Sens |
|---|---|
| Valeur ? Valeur : Valeur | Évaluation conditionnelle |
| Valeur , Valeur | Évaluer toutes les valeurs, puis ignorer toutes les valeurs à l’exception de la valeur la plus à droite |
Macros dans les expressions C++
Vous pouvez utiliser des macros dans des expressions C++. Vous devez ajouter un signe numérique (#) avant les macros.
Vous pouvez utiliser les macros suivantes. Ces macros ont les mêmes définitions que les macros Microsoft Windows portant le même nom. Les macros Windows sont définies dans Winnt.h.
| Macro | Valeur retournée |
|---|---|
| #CONTAINING_RECORD(Adresse, Type, Champ) | Retourne l’adresse de base d’une instance d’une structure, en fonction du type de la structure et de l’adresse d’un champ dans la structure. |
| #FIELD_OFFSET(Type, Champ) | Retourne le décalage d’octet d’un champ nommé dans un type de structure connu. |
| #RTL_CONTAINS_FIELD(Structure, Taille, Champ) | Indique si la taille d’octet donnée inclut le champ souhaité. |
| #RTL_FIELD_SIZE(Type, Champ) | Retourne la taille d’un champ dans une structure de type connu, sans nécessiter le type du champ. |
| #RTL_NUMBER_OF(Array) | Retourne le nombre d’éléments d’un tableau de taille statique. |
| #RTL_SIZEOF_THROUGH_FIELD(Type, Champ) | Retourne la taille d’une structure de type connu, jusqu'à et y compris un champ spécifié. |
Cet exemple montre l’utilisation de la #FIELD_OFFSET macro pour calculer le décalage d’octet sur un champ d’une structure.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
Voir aussi
Expressions MASM et expressions C++