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 L
sufijos , U
y 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 new
operadores , delete
y 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++