Expressões em C++ nativo
O depurador aceita a maioria das expressões C/C++ e Microsoft. O depurador também fornece funções intrínsecas e operadores de contexto para criar expressões de avaliação mais seguras e mais convenientes. Este tópico também descreve as limitações em expressões C++. Para usá-las, você precisa estar ciente do seguinte:
Você não pode usar o operador de contexto ou a maioria dos especificadores de formato em código ou com expressões de script ou código gerenciado. Elas são específicas para o avaliador de expressão C++ nativa.
Nesta seção
Usando funções intrínsecas do depurador para manter o estado
Usando operadores de contexto para especificar um símbolo
Restrições em expressões C++ nativas
Controle de acesso
Referências ambíguas
Namespaces anônimos
Construtores, destruidores e conversões
Herança
Funções embutidas e intrínsecas do compilador
Constantes numéricas
Funções do operador
Sobrecarga
Precedência
Formatos de símbolo
Conversão de tipo
Usando funções intrínsecas do depurador para manter o estado
As funções intrínsecas do depurador oferecem uma maneira de chamar determinadas funções C/C++ em expressões sem alterar o estado do aplicativo.
Funções intrínsecas do depurador:
São certamente seguras: executar uma função intrínseca do depurador não corromperá o processo que está sendo depurado.
São permitidas em todas as expressões, mesmo em cenários onde os efeitos colaterais e a avaliação de função não são permitidos.
Trabalham em cenários onde as chamadas de funções normais não são possíveis, por exemplo, depurar um minidespejo.
As funções intrínsecas do depurador também podem tornar mais convenientes as expressões de avaliação. Por exemplo, strncmp(str, “asd”) é muito mais fácil de escrever em uma condição de ponto de interrupção que str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’. )
Área |
Funções intrínsecas |
---|---|
Comprimento de cadeias de caracteres |
strlen, wcslen, strnlen, wcsnlen |
Comparação de cadeias de caracteres |
strcmp, wcscmp, stricmp, _stricmp, _strcmpi, wcsicmp, _wcscmpi, _wcsnicmp, strncmp, wcsncmp, strnicmp, wcsnicmp |
Pesquisa de cadeias de caracteres |
strchr, wcschr, strstr, wcsstr |
Win32 |
GetLastError(), TlsGetValue() |
Windows 8 |
WindowsGetStringLen(), WindowsGetStringRawBuffer() Essas funções exigem que o processo que está sendo depurado seja executado no Windows 8. Depurar os arquivos de despejo gerados a partir de um dispositivo do Windows 8 também exige que o computador do Visual Studio esteja executando o Windows 8. No entanto, se você estiver depurando um dispositivo do Windows 8 remotamente, o computador do Visual Studio poderá executar o Windows 7. |
Diversos |
__log2 Retorna a base 2 de log de um inteiro especificado, arredondada para o menor inteiro próximo. |
Usando operadores de contexto para especificar um símbolo
O operador de contexto é um operador adicional fornecido pelo depurador nativo. Ao depurar o código nativo, você poderá usar o operador de contexto para qualificar um local de ponto de interrupção, nome de variável ou expressão. O operador de contexto é útil para fins como especificar um nome de um escopo externo que, de outra forma, seria ocultado por um nome local.
Sintaxe
{,,[module] } expression
module é o nome de um módulo. Você pode usar um caminho completo para resolver a ambiguidade entre módulos com o mesmo nome.
expression é qualquer expressão C++ válida que seja resolvida para um destino válido, como um nome de função, nome de variável ou endereço do ponteiro no module.
As chaves devem conter duas vírgulas e o nome do módulo (executável ou DLL) ou o caminho completo.
Por exemplo, para definir um ponto de interrupção na função SomeFunction de EXAMPLE.dll:
{,,EXAMPLE.dll}SomeFunction
Se o caminho do module inclui uma vírgula, um espaço inserido ou uma chave, você deverá usar aspas em torno do caminho de modo que o analisador de contexto possa reconhecer corretamente a cadeia de caracteres. As aspas simples são consideradas parte de um nome de arquivo do Windows, portanto, você deve usar aspas duplas. Por exemplo,
{,"a long, long, library name.dll", } g_Var
Quando o avaliador de expressão localiza um símbolo em uma expressão, procura pelo símbolo na seguinte ordem:
Escopo léxico externo, começando com o bloco atual, série de instruções incluídas entre chaves e a continuação externa com o bloco delimitador. O bloco atual é o código que contém o local atual, endereço do ponteiro de instrução.
Escopo da função. A função atual.
Escopo da classe, se o local atual estiver dentro de uma função de membro C ++. O escopo da classe inclui todas as classes base. O avaliador de expressão usa regras de dominância normais.
Símbolos globais no módulo atual.
Símbolos públicos no programa atual.
Com o operador de contexto, você especifica o módulo inicial da pesquisa e ignora o local atual.
Restrições em expressões C++ nativas
Quando você insere a expressão C/C++ em uma janela do depurador, essas restrições gerais se aplicam:
Controle de acesso
O depurador pode acessar todos os membros de classe independentemente do controle de acesso. Você pode examinar qualquer membro do objeto de classe, incluindo classes base e objetos de membro inseridos.
Referências ambíguas
Se uma expressão do depurador se refere a um nome de membro ambíguo, você deverá usar o nome da classe para qualificá-lo. Por exemplo, se CObject for uma instância de CClass, que herda as funções de membro chamadas expense do AClass e BClass, CObject.expense será ambígua. Você pode resolver a ambiguidade da seguinte maneira:
CObject.BClass::expense
Para resolver ambiguidades, o avaliador de expressão aplica regras de dominância normais em relação aos nomes de membro.
Namespaces anônimos
O avaliador de expressão C++ nativa não oferece suporte a namespaces anônimos. Suponha, por exemplo, que você tenha o seguinte código:
#include "stdafx.h"
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
A única maneira de observar o símbolo test neste exemplo é usar o nome decorado:
(int*)?test@?A0xccd06570@mars@@3HA
Construtores, destruidores e conversões
Você não pode chamar um construtor ou um destruidor para um objeto, explicitamente ou implicitamente, usando uma expressão que exige a construção de um objeto temporário. Por exemplo, a expressão a seguir chama explicitamente um construtor e resulta em uma mensagem de erro:
Date( 2, 3, 1985 )
Você não pode chamar uma função de conversão se o destino da conversão for uma classe. Essa conversão envolve a construção de um objeto. Por exemplo, se myFraction for uma instância de CFraction, que define o operador da função de conversão FixedPoint, a expressão a seguir resultará em erro:
(FixedPoint)myFraction
No entanto, você pode chamar uma função de conversão se o destino da conversão for um tipo interno. Se CFraction definir uma função de conversão operator float, a seguinte expressão será válida no depurador:
(float)myFraction
Você pode chamar funções que retornam um objeto ou declaram objetos locais.
Você não pode chamar os operadores new ou delete. A expressão a seguir não funciona no depurador:
new Date(2,3,1985)
Herança
Quando você usar o depurador para exibir um objeto de classe que tem as classes base virtuais, os membros da classe base virtual serão exibidos para cada caminho de herança, embora apenas uma instância desses membros seja armazenada.
As chamadas de função virtual são tratadas corretamente pelo avaliador de expressão. Por exemplo, suponha que a classe CEmployee defina uma função virtual computePay, que é redefinida em uma classe que herda de CEmployee. Você pode chamar computePay por um ponteiro para CEmployee e a função adequada ser executada:
empPtr->computePay()
Você pode converter um ponteiro para um objeto de classe derivada em um ponteiro para um objeto de classe base. Você pode converter um ponteiro para um objeto de classe base em um ponteiro para um objeto de classe derivada, exceto quando a herança for virtual.
Funções embutidas e intrínsecas do compilador
Uma expressão do depurador não pode chamar funções intrínsecas ou uma função embutida de um compilador a menos que a função apareça pelo menos uma vez como uma função normal.
Constantes numéricas
As expressões do depurador podem usar constantes de inteiro em formato octal, hexadecimal ou decimal. Por padrão, o depurador espera constantes decimais. Essa configuração pode ser alterada na página Geral da guia Depurando.
Você pode usar símbolos de prefixo ou sufixo para representar números em outra base. A tabela a seguir mostra os formatos que você pode usar.
Sintaxe |
Exemplo (decimal 100) |
Base |
---|---|---|
digits |
100 ou 64 |
Decimal ou hexadecimal, dependendo da configuração atual. |
0 digits |
0144 |
Octal (base 8) |
0n digits |
0n100 |
Decimal (base 10) |
0x digits |
0x64 |
Hexadecimal (base 16) |
digits h |
64h |
Hexadecimal (base 16) |
Funções do operador
Uma expressão do depurador pode invocar funções do operador para uma classe implícita ou explicitamente. Por exemplo, suponha que myFraction e yourFraction sejam instâncias de uma classe que define operator+. Você pode exibir a soma desses dois objetos usando essa expressão:
myFraction + yourFraction
Se uma função do operador for definida como um amigo, você poderá chamá-lo implicitamente usando a mesma sintaxe que uma função de membro ou pode invocá-la explicitamente, da seguinte maneira:
operator+( myFraction, yourFraction )
Como funções comuns, as funções do operador não podem ser chamadas com argumentos que exigem uma conversão que envolve a construção do objeto.
O depurador não dá suporte a operadores sobrecarregados com versões const e não const. Os operadores sobrecarregados com versões const e não const são usados com frequência na biblioteca de modelos padrão.
Sobrecarga
Uma expressão do depurador pode chamar funções sobrecarregadas se existir uma correspondência exata ou se uma correspondência não exigir uma conversão que envolva a construção do objeto. Por exemplo, se a função calc utilizar um objeto CFraction como um parâmetro e a classe CFraction definir um construtor de argumento único que aceita um inteiro, a seguinte expressão resultará em um erro:
calc( 23 )
Mesmo que uma conversão legal exista para converter o inteiro no objeto CFraction que calc espera, essa conversão envolverá a criação de um objeto e não terá suporte.
Precedência
Em expressões de depurador, o operador do escopo C++ (::) tem uma precedência mais baixa do que no código-fonte. No código-fonte C++, esse operador tem a precedência mais alta. No depurador, sua prioridade está entre os operadores base e de sufixo (->, ++, --) e os operadores unários (!, &, *, dentre outros).
Formatos de símbolo
Você insere uma expressão de depurador que contém símbolos no mesmo formato usado no código-fonte, contanto que os símbolos estejam em um módulo compilado com informações de depuração completas (/Zi ou /ZI). Se você inserir uma expressão que contém símbolos públicos, que são símbolos encontrados em bibliotecas ou módulos compilados com /Zd, deverá usar o nome decorado do símbolo, o formato usado no código do objeto. Para obter mais informações, consulte /Z7, /Zd, /Zi, /ZI (formato de informação de depuração).
Você pode obter uma lista de todos os nomes em suas formas decoradas e não decoradas usando a opção LINK /MAP. Para obter mais informações, consulte /MAP (Gerar Mapfile).
A decoração de nome é o mecanismo usado para impor vinculação fortemente tipada. Isso significa que somente os nomes e as referências com ortografia, casos, convenção de chamada e tipos precisamente compatíveis são vinculados.
Os nomes declarados com a convenção de chamada de C, implícita ou explicitamente usando a palavra-chave _cdecl, começam com um sublinhado ( _ ). Por exemplo, a função main pode ser exibida como _main. Os nomes declarados como _fastcall começam com o símbolo @.
Para C++, o nome decorado codifica o tipo do símbolo além da convenção de chamada. O formato do nome pode ser longo e difícil de ler. O nome começa com pelo menos um ponto de interrogação (?). Para funções C++, a decoração inclui o escopo da função, os tipos de parâmetros da função e o tipo de retorno de função.
Conversão de tipo
Se você converter em um tipo, o tipo deverá ser conhecido do depurador. Você deve ter outro objeto desse tipo em seu programa. Os tipos criados usando instruções typedef não têm suporte.