Números y operadores de C++

En este artículo se describe el uso de la sintaxis de expresiones de C++ con las herramientas de depuración de Windows.

El depurador acepta dos tipos diferentes de expresiones numéricas: expresiones de C++ y expresiones de Ensamblador de macros de Microsoft (MASM). Cada una de estas expresiones sigue sus propias reglas de sintaxis para la entrada y salida.

Para obtener más información sobre cuándo se usa cada tipo de sintaxis, vea Evaluación de expresiones y el comando ? evaluate expression .

El analizador de expresiones de C++ admite todas las formas de sintaxis de expresión de C++. La sintaxis incluye todos los tipos de datos, incluidos punteros, números de punto flotante y matrices, y todos los operadores unarios y binarios de C++.

Las ventanas Inspección y Variables locales del depurador siempre usan el evaluador de expresiones de C++.

En el ejemplo siguiente, el comando evaluar expresión de C++ muestra el valor del registro del puntero de instrucción.

0:000> ?? @eip
unsigned int 0x771e1a02

Podemos usar la función de C++ sizeof para determinar el tamaño de las estructuras.

0:000> ?? (sizeof(_TEB))
unsigned int 0x1000

Establecer el evaluador de expresiones en C++

Use el evaluador de expresiones .expr choose para ver el evaluador de expresiones predeterminado y cambiarlo a C++.

0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions

Una vez cambiado el evaluador de expresiones predeterminado, se puede usar el comando ? evaluate expression para mostrar expresiones de C++. En el ejemplo siguiente se muestra el valor del registro del puntero de instrucción.

0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02

Para obtener más información sobre la referencia de @eip registro, consulte Register syntax (Registrar sintaxis).

En este ejemplo, el valor hexadecimal de 0xD se agrega al registro de eip.

0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f

Registros y pseudo-registros en expresiones de C++

Puede usar registros y pseudo-registros en expresiones de C++. El signo @ debe agregarse antes del registro o pseudo-registro.

El evaluador de expresiones realiza automáticamente la conversión adecuada. Los registros reales y los pseudo-registros enteros se convierten en ULONG64. Todas las direcciones se convierten en PUCHAR, se convierte ETHREAD*en , $proc se convierte EPROCESS*en , $teb se convierte en TEB*y $peb se convierte en PEB*$thread .

En este ejemplo se muestra el 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

No se puede cambiar un registro o pseudo-registro mediante una asignación o un operador de efecto secundario. Debe usar el comando r registers para cambiar estos valores.

En el ejemplo siguiente se establece el pseudo registro en un valor de 5 y, a continuación, se muestra.

0:000> r $t0 = 5

0:000> ?? @$t0
unsigned int64 5

Para obtener más información sobre los registros y pseudo-registros, vea Registrar sintaxis y Pseudo-register sintaxis.

Números en expresiones de C++

Los números en expresiones de C++ se interpretan como números decimales, a menos que los especifique de otra manera. Para especificar un entero hexadecimal, agregue 0x antes del número. Para especificar un entero octal, agregue 0 (cero) antes del número.

El radix predeterminado del depurador no afecta a cómo se escriben expresiones de C++. No puede escribir directamente un número binario, excepto anidando una expresión MASM dentro de la expresión de C++.

Puede escribir un valor hexadecimal de 64 bits en el formato xxxxxxxx'xxxxxxxx. También puedes omitir el acento grave ('). Ambos formatos generan el mismo valor.

Puede usar los Lsufijos , Uy I64 con valores enteros. El tamaño real del número que se crea depende del sufijo y del número que escriba. Para obtener más información sobre esta interpretación, vea una referencia del lenguaje C++.

La salida del evaluador de expresiones de C++ mantiene el tipo de datos que especifican las reglas de expresión de C++. Sin embargo, si usa esta expresión como argumento para un comando, siempre se realiza una conversión. Por ejemplo, no es necesario convertir valores enteros en punteros cuando se usan como direcciones en argumentos de comando. Si el valor de la expresión no se puede convertir válidamente en un entero o un puntero, se produce un error de sintaxis.

Puede usar el 0n prefijo (decimal) para alguna salida, pero no puede usarlo para la entrada de expresión de C++.

Caracteres y cadenas en expresiones de C++

Puede escribir un carácter al rodearlo con comillas simples ('). Se permiten los caracteres de escape estándar de C++.

Puede escribir literales de cadena si los rodea con comillas dobles ("). Puede usar \" como una secuencia de escape dentro de dicha cadena. Sin embargo, las cadenas no tienen ningún significado para el evaluador de expresiones.

Símbolos en expresiones de C++

En una expresión de C++, cada símbolo se interpreta según su tipo. Dependiendo de lo que hace referencia el símbolo, puede interpretarse como un entero, una estructura de datos, un puntero de función o cualquier otro tipo de datos. Se produce un error de sintaxis si usa un símbolo que no se corresponde con un tipo de datos de C++, como un nombre de módulo sin modificar, dentro de una expresión de C++.

Puede usar un énfasis grave (') o un apóstrofo (') en un nombre de símbolo solo si agrega un nombre de módulo y un signo de exclamación antes del nombre del símbolo. Al agregar los < delimitadores y > después de un nombre de plantilla, puede agregar espacios entre estos delimitadores.

Si el símbolo puede ser ambiguo, puede agregar un nombre de módulo y un signo de exclamación (!) o solo un signo de exclamación antes del símbolo. Para especificar que un símbolo está pensado para ser local, omita el nombre del módulo e incluya un signo de dólar y un signo de exclamación ($!) antes del nombre del símbolo. Para obtener más información sobre el reconocimiento de símbolos, vea Sintaxis de símbolos y coincidencia de símbolos.

Estructuras en expresiones de C++

El evaluador de expresiones de C++ convierte pseudo-registers en sus tipos adecuados. Por ejemplo, $teb se convierte como .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

En el ejemplo siguiente se muestra el identificador de proceso en la estructura TEB que muestra el uso de un puntero a un miembro de la estructura a la que se hace referencia.

0:000> ??  @$teb->ClientId.UniqueProcess
void * 0x0000059c

Operadores en expresiones de C++

Puede usar paréntesis para invalidar las reglas de precedencia.

Si incluye parte de una expresión de C++ entre paréntesis y agrega dos a signos (@@) antes de la expresión, la expresión se interpreta según las reglas de expresión de MASM. No se puede agregar un espacio entre los dos signos y el paréntesis de apertura. El valor final de esta expresión se pasa al evaluador de expresiones de C++ como un valor de ULONG64. También puede especificar el evaluador de expresiones mediante @@c++( ... ) o @@masm( ... ).

Los tipos de datos se indican como de costumbre en el lenguaje C++. Se reconocen todos los símbolos que indican matrices ([ ]), miembros de puntero (->), miembros UDT (.) y miembros de clases (::). Se admiten todos los operadores aritméticos, incluidos los operadores de asignación y efecto secundario. Sin embargo, no se pueden usar los newoperadores , deletey throw y no se puede llamar realmente a una función.

Se admite la aritmética de punteros y los desplazamientos se escalan correctamente. Tenga en cuenta que no se puede agregar un desplazamiento a un puntero de función. Si debe agregar un desplazamiento a un puntero de función, convierta primero el desplazamiento en un puntero de caracteres.

Como en C++, si usa operadores con tipos de datos no válidos, se produce un error de sintaxis. El analizador de expresiones de C++ del depurador usa reglas ligeramente más relajadas que la mayoría de los compiladores de C++, pero se aplican todas las reglas principales. Por ejemplo, no se puede cambiar un valor no entero.

Puede usar los operadores siguientes. Los operadores de cada celda tienen prioridad sobre los operadores de las celdas inferiores. Los operadores de la misma celda tienen la misma prioridad y se analizan de izquierda a derecha.

Al igual que con C++, la evaluación de expresiones finaliza cuando se conoce su valor. Este final le permite usar de forma eficaz expresiones como ?? myPtr && *myPtr.

Referencia y conversión de tipos

Operator Significado
Expresión // Comentario Omitir todo el texto posterior
Clase :: Miembro Miembro de la clase
Clase ::~Member Miembro de la clase (destructor)
:: Nombre Global
Estructura . Campo Campo de una estructura
Puntero ->Field Campo de la estructura a la que se hace referencia
Nombre [entero] Subíndice de matriz
LValue ++ Incremento (después de la evaluación)
LValue -- Decremento (después de la evaluación)
< dynamic_castTipo>(Valor) Difusión de tipos (siempre realizada)
Static_cast<Tipo>(Valor) Difusión de tipos (siempre realizada)
< reinterpret_castTipo>(Valor) Difusión de tipos (siempre realizada)
< const_castTipo>(Valor) Difusión de tipos (siempre realizada)

Operaciones de valor

Operator Significado
(tipo) Valor Difusión de tipos (siempre realizada)
sizeofvalue Tamaño de la expresión
sizeof( type ) Tamaño del tipo de datos
++ LValue Incremento (antes de la evaluación)
-- LValue Decremento (antes de la evaluación)
~ Valor Complemento de bits
! Valor No (booleano)
Valor Resta unaria
+ Valor Suma unaria
& LValue Dirección del tipo de datos
Valor Dereference
Estructura . Puntero Puntero a miembro de la estructura
Puntero -> * Puntero Puntero al miembro de la estructura a la que se hace referencia

Aritméticos

Operator Significado
Valor de valor Multiplicación
Valor / Valor División
Valor % Valor Módulo
Valor + Valor Suma
Valor - Valor Resta
Valor<<Valor Desplazamiento bit a bit a la izquierda
Valor>>Valor Desplazamiento bit a bit a la derecha
Valor<Valor Menor que (comparación)
Valor<= Valor Menor o igual que (comparación)
Valor>Valor Mayor que (comparación)
Valor>= Valor Mayor o igual que (comparación)
Valor == Valor Igual (comparación)
Valor != Valor No es igual (comparación)
Valor & Valor AND bit a bit
Valor ^ Valor XOR bit a bit (OR exclusivo)
Valor | Valor OR bit a bit
Valor && Valor Y lógico
Valor || Valor O lógico

En los ejemplos siguientes se supone que los pseudo registros se establecen como se muestra.

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

Asignación

Operator Significado
LValue = Valor Asignar
LValue *= Valor Multiplicar y asignar
LValue /= Valor Dividir y asignar
LValue %= Valor Módulo y asignar
LValue += Valor Sumar y asignar
LValue -= Valor Restar y asignar
LValue<<= Valor Desplazamiento a la izquierda y asignación
LValue>>= Valor Desplazar a la derecha y asignar
LValue &= Valor AND y asignar
LValue |= Valor OR y asignar
LValue ^= Valor XOR y asignación

Evaluación

Operator Significado
¿Valor ? Valor : Valor Evaluación condicional
Valor , Valor Evalúe todos los valores y, a continuación, descarte todo excepto el valor más a la derecha.

Macros en expresiones de C++

Puede usar macros en expresiones de C++. Debe agregar un signo de número (#) antes de las macros.

Puede usar las macros siguientes. Estas macros tienen las mismas definiciones que las macros de Microsoft Windows con el mismo nombre. Las macros de Windows se definen en Winnt.h.

Macro Valor devuelto
#CONTAINING_RECORD(Address, Type, Field) Devuelve la dirección base de una instancia de una estructura, dado el tipo de la estructura y la dirección de un campo dentro de la estructura.
#FIELD_OFFSET(Type, Field) Devuelve el desplazamiento de bytes de un campo con nombre en un tipo de estructura conocido.
#RTL_CONTAINS_FIELD(Struct, Size, Field) Indica si el tamaño de bytes especificado incluye el campo deseado.
#RTL_FIELD_SIZE(Type, Field) Devuelve el tamaño de un campo en una estructura de tipo conocido, sin necesidad del tipo del campo.
#RTL_NUMBER_OF(Array) Devuelve el número de elementos de una matriz de tamaño estático.
#RTL_SIZEOF_THROUGH_FIELD(Type, Field) Devuelve el tamaño de una estructura de tipo conocido, hasta hasta un campo especificado.

En este ejemplo se muestra el uso de la #FIELD_OFFSET macro para calcular el desplazamiento de bytes en un campo de una estructura.

0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2

Consulte también

Expresiones masm frente a expresiones de C++

?? evaluar expresión de C++

? evaluar expresión

.expr choose expression evaluador

Extensión de inicio de sesión

Ejemplos de expresiones mixtas