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 del 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 expresiones 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 de expresión ?? evaluate 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 .expr choose expression evaluador 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 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 de valores enteros se convierten en ULONG64. Todas las direcciones se convierten en PUCHAR, $thread se convierten en ETHREAD*, $proc se convierten en EPROCESS*, $teb se convierten en TEB*y $peb se convierten en PEB*.

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

Un operador de asignación o efecto secundario no puede cambiar un registro o un pseudo-registro. 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-registers, vea Register syntax and Pseudo-register syntax(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 puede 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 algunos resultados, 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 corresponde a 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 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 puede usar los newoperadores , deletey throw y no puede llamar realmente a una función.

Se admite la aritmética de puntero 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 siguientes operadores. 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

Operador Significado
Comentario de expresión // 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_cast type>(Value) Typecast (siempre realizado)
<static_cast type>(Value) Typecast (siempre realizado)
<reinterpret_cast type>(Value) Typecast (siempre realizado)
<const_cast type>(Value) Typecast (siempre realizado)

Operaciones de valor

Operador Significado
(tipo) Valor Typecast (siempre realizado)
sizeof value 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 bit
! Valor No (booleano)
Valor Unario menos
+ Valor Suma unaria
& LValue Dirección del tipo de datos
Valor Dereference
Estructura. Puntero Puntero al miembro de la estructura
Puntero -> * Puntero Puntero al miembro de la estructura a la que se hace referencia

Aritméticos

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

Cesión

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

Evaluación

Operador 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 siguientes macros. 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 e incluye 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 elegir evaluador de expresiones

Extensión de firma

Ejemplos de expresiones mixtas