Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Este artigo descreve o uso da sintaxe de expressão C++ com as ferramentas de depuração do Windows.
O depurador aceita dois tipos diferentes de expressões numéricas: expressões C++ e expressões Microsoft Macro Assembler (MASM). Cada uma dessas expressões segue suas próprias regras de sintaxe para entrada e saída.
Para obter mais informações sobre quando cada tipo de sintaxe é usado, consulte Avaliando expressões e o comando ? evaluate expression .
O analisador de expressões C++ suporta todas as formas de sintaxe de expressão C++. A sintaxe inclui todos os tipos de dados, incluindo ponteiros, números de vírgula flutuante e matrizes, e todos os operadores binários e unários C++.
As janelas Watch e Locals no depurador sempre usam o avaliador de expressão C++.
No exemplo a seguir, o comando ?? evaluate C++ expression exibe o valor do registo do ponteiro de instruções.
0:000> ?? @eip
unsigned int 0x771e1a02
Podemos usar a função C++ sizeof para determinar o tamanho das estruturas.
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Definir o avaliador de expressão como C++
Use o .expr escolher avaliador de expressões para visualizar o avaliador de expressões padrão e alterá-lo para C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
Depois que o avaliador de expressão padrão for alterado, o comando ? evaluate expression poderá ser usado para exibir expressões C++. O exemplo a seguir exibe o valor do registo do ponteiro de instrução.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Para saber mais sobre a referência de registo, consulte @eipSintaxe de registo.
Neste exemplo, o valor hexadecimal de 0xD é adicionado ao registro eip.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Registradores e pseudo-registros em expressões C++
Você pode usar registradores e pseudo-registros em expressões C++. O sinal @ deve ser adicionado antes do registo ou pseudo-registo.
O avaliador de expressões executa automaticamente o elenco adequado. Registros reais e pseudo-registros de valor inteiro são convertidos em ULONG64. Todos os endereços são lançados para PUCHAR, $thread é moldado para ETHREAD*, $proc é moldado para EPROCESS*, $teb é moldado para TEB*, e $peb é lançado para PEB*.
Este exemplo exibe o 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
Não podes alterar um registo ou pseudo-registo através de um operador de atribuição ou de efeito colateral. Você deve usar o comando r registers para alterar esses valores.
O exemplo a seguir define o pseudo registro como um valor de 5 e, em seguida, o exibe.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Para obter mais informações sobre registros e pseudo-registros, consulte Sintaxe de registro e sintaxe de pseudo-registro.
Números em expressões C++
Os números em expressões C++ são interpretados como números decimais, a menos que você os especifique de outra maneira. Para especificar um inteiro hexadecimal, adicione 0x antes do número. Para especificar um número inteiro octal, adicione 0 (zero) antes do número.
O radix do depurador padrão não afeta como você insere expressões C++. Não é possível inserir diretamente um número binário, exceto aninhando uma expressão MASM na expressão C++.
Você pode inserir um valor hexadecimal de 64 bits no formato xxxxxxxx'xxxxxxxx. Pode também omitir o acento grave ('). Ambos os formatos produzem o mesmo valor.
Você pode usar os sufixos L, Ue I64 com valores inteiros. O tamanho real do número criado depende do sufixo e do número inserido. Para obter mais informações sobre essa interpretação, consulte uma referência de linguagem C++.
A saída do avaliador de expressão C++ mantém o tipo de dados especificado pelas regras de expressão C++. No entanto, se você usar essa expressão como um argumento para um comando, uma conversão será sempre feita. Por exemplo, você não precisa converter valores inteiros em ponteiros quando eles são usados como endereços em argumentos de comando. Se o valor da expressão não puder ser convertido validamente para um inteiro ou um ponteiro, ocorrerá um erro de sintaxe.
Você pode usar o prefixo 0n (decimal) para alguma saída, mas não pode usá-lo para entrada de expressão C++.
Caracteres e cadeias de caracteres em expressões C++
Você pode inserir um caractere cercando-o com aspas simples ('). Os caracteres de escape C++ padrão são permitidos.
Você pode inserir literais de cadeias colocando-os entre aspas. Você pode usar \" como uma sequência de escape dentro dessa cadeia de caracteres. No entanto, as cadeias de caracteres não têm significado para o avaliador de expressão.
Símbolos em expressões C++
Em uma expressão C++, cada símbolo é interpretado de acordo com seu tipo. Dependendo do que o símbolo se refere, ele pode ser interpretado como um inteiro, uma estrutura de dados, um ponteiro de função ou qualquer outro tipo de dados. Um erro de sintaxe ocorre se você usar um símbolo que não corresponde a um tipo de dados C++, como um nome de módulo não modificado, dentro de uma expressão C++.
Você pode usar um acento grave (') ou um apóstrofo (') em um nome de símbolo somente se você adicionar um nome de módulo e ponto de exclamação antes do nome do símbolo. Ao adicionar os delimitadores < e > após o nome de um modelo, pode adicionar espaços entre esses delimitadores.
Se o símbolo pode ser ambíguo, você pode adicionar um nome de módulo e um ponto de exclamação (!) ou apenas um ponto de exclamação antes do símbolo. Para especificar que um símbolo deve ser local, omita o nome do módulo e inclua um cifrão e um ponto de exclamação ($!) antes do nome do símbolo. Para obter mais informações sobre reconhecimento de símbolos, consulte Sintaxe de símbolos e correspondência de símbolos.
Estruturas em expressões C++
O avaliador de expressões C++ converte os pseudo-registos para os seus tipos apropriados. Por exemplo, $teb é convertido para um 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
O exemplo a seguir exibe a ID do processo na estrutura TEB mostrando o uso de um ponteiro para um membro da estrutura referenciada.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Operadores em expressões C++
Você pode usar parênteses para substituir regras de precedência.
Se você colocar parte de uma expressão C++ entre parênteses e adicionar dois sinais ( @@) antes da expressão, a expressão será interpretada de acordo com as regras de expressão do MASM. Não é possível adicionar um espaço entre os dois sinais de arroba e o parêntese de abertura. O valor final desta expressão é passado para o avaliador de expressões C++ como um valor ULONG64. Você também pode especificar o avaliador de expressão usando @@c++( ... ) ou @@masm( ... ).
Os tipos de dados são indicados como de costume na linguagem C++. Os símbolos que indicam matrizes ([ ]), membros de ponteiro (->), membros UDT (.) e membros de classes (::) são todos reconhecidos. Todos os operadores aritméticos são suportados, incluindo operadores de atribuição e de efeito colateral. No entanto, você não pode usar o new, deletee throw operadores, e você não pode realmente chamar uma função.
A aritmética de ponteiros é suportada e os offsets são escalonados corretamente. Observe que não é possível adicionar um deslocamento a um ponteiro de função. Se precisar adicionar um deslocamento a um ponteiro de função, converta o deslocamento num ponteiro de carácter primeiro.
Como em C++, se você usar operadores com tipos de dados inválidos, ocorrerá um erro de sintaxe. O analisador de expressões C++ do depurador utiliza regras um pouco mais flexíveis do que a maioria dos compiladores C++, mas todas as regras principais são rigorosamente aplicadas. Por exemplo, não é possível deslocar um valor não inteiro.
Você pode usar os seguintes operadores. Os operadores em cada célula têm precedência sobre os operadores nas células inferiores. Os operadores na mesma célula têm a mesma precedência e são analisados da esquerda para a direita.
Tal como acontece com C++, a avaliação de expressão termina quando o seu valor é conhecido. Essa terminação permite que você use efetivamente expressões como ?? myPtr && *myPtr.
Fundição de referência e tipo
| Operador | Significado |
|---|---|
| Expressão // Comentar | Ignorar todo o texto subsequente |
| Classe :: Membro | Membro da classe |
| Classe ::~Membro | Membro da classe (destruidor) |
| :: Nome | A nível mundial |
| Estrutura . Campo | Campo numa estrutura |
| Ponteiro ->Campo | Campo na estrutura referenciada |
| Nome [inteiro] | Índice de matriz |
| LValue ++ | Incremento (após avaliação) |
| LValue -- | Decréscimo (após avaliação) |
| dynamic_cast<tipo>(Valor) | Typecast (sempre realizado) |
| static_cast<tipo>(Valor) | Typecast (sempre realizado) |
| reinterpret_cast<tipo>(Valor) | Typecast (sempre realizado) |
| const_cast<tipo>(Value) | Typecast (sempre realizado) |
Operações de valor
| Operador | Significado |
|---|---|
| (tipo) Valor | Typecast (sempre realizado) |
| tamanhodovalor | Tamanho da expressão |
| sizeof( tipo ) | Tamanho do tipo de dados |
| ++ LValue | Incremento (antes da avaliação) |
| -- LValue | Decréscimo (antes da avaliação) |
| ~ valor | Complemento de bits |
| ! Value | Não (Booleano) |
| Value | Unário menos |
| + valor | Unário mais |
| & LValue | Endereço de um tipo de dados |
| Value | Desreferenciação |
| Estrutura . Pointer | Ponteiro para membro da estrutura |
| Ponteiro -> * Ponteiro | Ponteiro para membro da estrutura referenciada |
Aritmética
| Operador | Significado |
|---|---|
| Valor do valor | Multiplicação |
| Valor / Valor | Divisão |
| Valor % Valor | Módulos |
| Valor + Valor | Adição |
| Valor - Valor | Subtração |
| Valor<<Valor | Deslocar bitwise para a esquerda |
| Valor>>Valor | Deslocamento bitwise para a direita |
| Valor<Valor | Menos de (comparação) |
| Valor<= Valor | Menor ou igual (comparação) |
| Valor>Valor | Maior que (comparação) |
| Valor>= Valor | Maior ou igual (comparação) |
| Valor == Valor | Igual (comparação) |
| Valor != Valor | Não igual (comparação) |
| Valor & Valor | Bitwise E |
| Valor ^ Valor | Bitwise XOR (OR exclusivo) |
| Valor | Valor | Bitwise OU |
| Valor && Valor | Lógica E |
| Valor || Valor | OU Lógico |
Os exemplos a seguir pressupõem que os pseudo-registros são definidos como mostrado.
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
Atribuição
| Operador | Significado |
|---|---|
| LValue = Valor | Atribuir |
| LValue *= Valor | Multiplicar e atribuir |
| LValue /= Valor | Dividir e atribuir |
| LValue %= Valor | Modulo e atribuir |
| LValue += Valor | Adicionar e atribuir |
| LValue -= Valor | Subtrair e atribuir |
| LValue<<= Valor | Deslocar para a esquerda e atribuir |
| LValue>>= Valor | Deslocar para a direita e atribuir |
| LValue &= Valor | E atribuir |
| LValue |= Valor | OU e atribuir |
| LValue ^= Valor | XOR e atribuir |
Avaliação
| Operador | Significado |
|---|---|
| Valor ? Valor : Valor | Avaliação condicional |
| Valor , Valor | Avalie todos os valores e, em seguida, descarte todos, exceto o valor mais à direita |
Macros em expressões C++
Você pode usar macros em expressões C++. Você deve adicionar um sinal numérico (#) antes das macros.
Você pode usar as seguintes macros. Essas macros têm as mesmas definições que as macros do Microsoft Windows com o mesmo nome. As macros do Windows são definidas em Winnt.h.
| Macro | Valor de retorno |
|---|---|
| #CONTAINING_RECORD(Endereço, Tipo, Campo) | Retorna o endereço base de uma instância de uma estrutura, dado o tipo da estrutura e o endereço de um campo dentro da estrutura. |
| #FIELD_OFFSET(Tipo, Campo) | Retorna o deslocamento de bytes de um campo nomeado em um tipo de estrutura conhecido. |
| #RTL_CONTAINS_FIELD(Estrutura, Tamanho, Campo) | Indica se o tamanho de byte fornecido inclui o campo desejado. |
| #RTL_FIELD_SIZE(Tipo, Campo) | Devolve o tamanho de um campo numa estrutura de tipo conhecido, sem exigir o tipo do campo. |
| #RTL_NUMBER_OF(Array) | Retorna o número de elementos em uma matriz de tamanho estático. |
| #RTL_SIZEOF_THROUGH_FIELD(Tipo, Campo) | Retorna o tamanho de uma estrutura de tipo conhecido, incluindo um campo especificado. |
Este exemplo mostra o uso da macro #FIELD_OFFSET para calcular o deslocamento de bytes para um campo numa estrutura.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
Ver também
Expressões MASM vs. expressões C++