Nombres et opérateurs C++

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 commande d’expression d’évaluation .

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 d’expression ?? evaluate C++ affiche la valeur du registre du 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 d’expression d’évaluation 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 de @eip registre, consultez la syntaxe Register.

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 PUCHARen , $thread ETHREAD*est castée en EPROCESS*, $proc est castée en , $teb est castée TEB*en , 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 et I64 Ules Lsuffixes 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 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 casté 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 du pointeur est prise en charge et les décalages sont correctement mis à l’échelle. 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 dans la même cellule ont 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 cast de type

Opérateur Signification
Commentaire d’expression // Ignorer tout le texte suivant
Classe :: Membre Membre de la classe
Classe ::~Member Membre de la classe (destructeur)
:: Nom Global
Structure. Champ Champ dans une structure
Pointeur ->Field Champ dans la structure référencée
Nom [entier] Indice de tableau
LValue ++ Incrémenter (après l’évaluation)
LValue -- Décrémentation (après évaluation)
><type(valeur) dynamic_cast Typecast (toujours effectué)
><type(valeur) static_cast Typecast (toujours effectué)
<reinterpret_cast type>(Valeur) Typecast (toujours effectué)
<const_cast type>(Valeur) Typecast (toujours effectué)

Opérations de valeur

Opérateur Signification
(type) Valeur Typecast (toujours effectué)
sizeof value Taille de l’expression
sizeof( type ) Taille du type de données
++ LValue Incrémenter (avant l’évaluation)
-- LValue Décrémentation (avant l’évaluation)
~ Valeur Complément bit
! Valeur Not (booléen)
Valeur Moins unaire
+ Valeur Plus unaire
& LValue Adresse du type de données
Valeur Dereference
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 Signification
Valeur Multiplication
Valeur / Division
Valeur % Modulo
Valeur + Addition
Valeur - Soustraction
Valeur<< Maj au niveau du bit vers la gauche
Valeur>> Maj au niveau du bit vers la droite
Valeur< Inférieur à (comparaison)
Value= Value= Value< Inférieur ou égal (comparaison)
Valeur> Supérieur à (comparaison)
Value= Value= Value> Supérieur ou égal à (comparaison)
Valeur == Égal (comparaison)
Valeur != Valeur Non égal (comparaison)
Valeur &valeur ET au niveau du bit
Valeur ^ XOR bit à bit (OU exclusif)
Valeur | Opération de bits OR
Valeur && Valeur ET logique
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

Affectation

Opérateur Signification
Valeur LValue = Affecter
Valeur LValue *= Multiplier et affecter
Valeur LValue /= Diviser et assigner
Valeur LValue %= Modulo et assigner
Valeur LValue += Additionner et assigner
Valeur LValue -= Soustraire et assigner
LValue<<= Value Maj vers la gauche et affectation
LValue>>= Value Maj vers la droite et affectation
LValue &= Value AND et assigner
Valeur LValue |= OR et assigner
Valeur LValue ^= XOR et assigner

Évaluation

Opérateur Signification
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(Struct, Size, Field) 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’à un champ spécifié et incluant 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++

?? évaluer l’expression C++

? évaluer l’expression

.expr choisir l’évaluateur d’expression

Signer l’extension

Exemples d’expressions mixtes