Condividi tramite


Espressioni in C++ nativo

Il debugger accetta la maggior parte delle espressioni C/C++ Microsoft e ANSI.Il debugger consente inoltre a funzioni intrinseche e operatori di contesto per semplificare le espressioni di valutazione più sicure e più utili.In questo argomento vengono descritte le limitazioni relative alle espressioni C++ che devono essere a conoscenza quanto segue:

L'operatore di contesto e la maggior parte degli identificatori di formato non possono essere utilizzati nel codice né con espressioni di script o di codice gestitoin quanto sono specifici dell'analizzatore di espressioni C++ nativo.

Contenuto della sezione

Utilizzo di funzioni intrinisic del debugger per mantenere lo stato

Utilizzo di operatori di contesto per specificare un simbolo

Limitazioni relative alle espressioni in linguaggio C++ nativo

  • Controllo di accesso

  • Riferimenti ambigui

  • Spazi dei nomi anonimi

  • Costruttori, conversioni e distruttori

  • Ereditarietà

  • Funzioni intrinseche del compilatore e inline

  • Costanti numeriche

  • Funzioni degli operatori

  • Overload

  • Precedenza

  • Formati di simbolo

  • Cast di tipo

Utilizzo di funzioni intrinisic del debugger per mantenere lo stato

Le funzioni intrinseche del debugger offrono un modo per chiamare alcune funzioni C/C++ nelle espressioni senza modificare lo stato dell'applicazione.

Funzioni intrinseche del debugger:

  • Sono garantiti per accertarsi: esecuzione di una funzione intrinseca del debugger non danneggerà il processo che stia eseguendo il debug.

  • Sono consentiti nelle espressioni, anche negli scenari in cui gli effetti collaterali e la valutazione della funzione non sono consentiti.

  • Lavoro negli scenari in cui le chiamate di funzione e non sono possibili, come eseguire il debug di minidump.

Le funzioni intrinseche del debugger è inoltre possibile semplificare le espressioni di valutazione più utili.Ad esempio, strncmp(str, “asd”) è molto più facile da scrivere in una condizione del punto di interruzione che str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’.)

Area

Funzioni intrinseche

Lunghezza della stringa

strlen, wcslen, strnlen, wcsnlen

Confronto tra stringhe

strcmp, wcscmp, stricmp, _stricmp, _strcmpi, wcsicmp, _wcscmpi, _wcsnicmp, strncmp, wcsncmp, strnicmp, wcsnicmp

Ricerca di stringhe

strchr, wcschr, strstr, wcsstr

Win32

GetLastError(), TlsGetValue()

Windows 8

WindowsGetStringLen(), WindowsGetStringRawBuffer()

Queste funzioni richiedono il processo sottoposto a debug in esecuzione su Windows 8.I file dump di debug ha generato da Windows 8 che il dispositivo richiede inoltre che il computer che esegue Visual Studio è in esecuzione Windows 8.Tuttavia, se si esegue il debug di un dispositivo Windows 8 in modalità remota, il computer che esegue Visual Studio può essere Windows 7 in esecuzione.

Varie

__log2

Restituisce la base 2 del registro di un intero specificato, arrotondata all'intero più basso più vicino.

Utilizzo di operatori di contesto per specificare un simbolo

L'operatore di contesto è un operatore aggiuntivo fornito dal debugger nativo.Quando il debug di codice nativo, è possibile utilizzare l'operatore di contesto per specificare la posizione di un punto di interruzione, un nome di variabile, o un'espressione.L'operatore di contesto è utile per specificare ad esempio un nome di un ambito esterno che verrebbe altrimenti nascosto da un nome locale.

Sintassi

{,,[modulo] } espressione

  • modulo è il nome di un modulo.È possibile utilizzare un percorso completo per distinguere tra i moduli con lo stesso nome.

  • espressione è qualsiasi espressione valida C++ che si risolve in un database di destinazione valido, ad esempio un nome di funzione, un nome di variabile, o un indirizzo del puntatore in modulo.

Le parentesi graffe devono contenere due virgole e il nome o il percorso completo del modulo (eseguibile o DLL).

Ad esempio, impostare un punto di interruzione nella funzione di SomeFunction di EXAMPLE.dll:

{,,EXAMPLE.dll}SomeFunction

Se il percorso di modulo include una virgola, uno spazio incorporato, o una parentesi graffa, è necessario utilizzare le virgolette intorno al percorso in modo da poter riconoscere correttamente il parser contesto della stringa.Poiché le virgolette singole vengono considerate parte di un nome di file di Windows, è necessario utilizzare le virgolette doppie.Di seguito è riportato un esempio:

{,"a long, long, library name.dll", } g_Var

Quando l'analizzatore di espressioni rileva un simbolo in un'espressione, ne esegue la ricerca nel seguente ordine:

  1. Ambito lessicale verso l'esterno, a partire dal blocco corrente, una serie di istruzioni racchiuse tra parentesi graffe, verso il blocco di inclusione.Il blocco corrente è il codice contenente la posizione corrente, ovvero l'indirizzo del puntatore all'istruzione (instruction pointer).

  2. Ambito della funzionecorrente.

  3. Ambito della classe, se la posizione corrente è all'interno di una funzione membro C++.Nell'ambito della classe sono incluse tutte le classi base.L'analizzatore di espressioni utilizza le normali regole di dominanza.

  4. Simboli globali del modulo corrente.

  5. Simboli pubblici nel programma corrente.

Con l'operatore di contesto, il modulo iniziale della ricerca e si ignora la posizione corrente.

Limitazioni relative alle espressioni in linguaggio C++ nativo

Quando si immette un'espressione C/C++ in una finestra del debugger, vengono applicate le seguenti restrizioni generali:

y2t7ahxk.collapse_all(it-it,VS.110).gifControllo di accesso

Il debugger può accedere a tutti i membri di classe indipendentemente dal controllo di accesso.È possibile esaminare qualsiasi membro di un oggetto classe, inclusi gli oggetti membro incorporati e le classi base.

y2t7ahxk.collapse_all(it-it,VS.110).gifRiferimenti ambigui

Se un'espressione del debugger fa riferimento a un nome di membro ambiguo, è necessario utilizzare il nome della classe per qualificarlo.Se ad esempio CObject è un'istanza di CClass, che eredita le funzioni membro denominate expense da AClass e BClass, CObject.expense risulterà ambiguo.È possibile risolvere tale ambiguità come segue:

CObject.BClass::expense

Per risolvere le ambiguità, l'analizzatore di espressioni applica le normali regole di dominanza relative ai nomi di membro.

y2t7ahxk.collapse_all(it-it,VS.110).gifSpazi dei nomi anonimi

L'analizzatore di espressioni in linguaggio C++ nativo non supporta gli spazi dei nomi anonimi.Si supponga, ad esempio, che esista il seguente codice:

#include "stdafx.h"

namespace mars 
{ 
    namespace
    {
        int test = 0; 
    } 

} 


int main() 
{ 
    // Adding a watch on test does not work. 
    mars::test++; 
    return 0; 
} 

L'unico modo per controllare il simbolo test in questo esempio consiste nell'utilizzare il nome decorato:

(int*)?test@?A0xccd06570@mars@@3HA

y2t7ahxk.collapse_all(it-it,VS.110).gifCostruttori, conversioni e distruttori

Non è possibile chiamare in modo implicito o esplicito un costruttore o un distruttore relativo a un oggetto, utilizzando un'espressione che richiede la costruzione di un oggetto temporaneo.La seguente espressione, ad esempio, chiama in modo esplicito un costruttore generando in questo modo un messaggio di errore:

Date( 2, 3, 1985 )

Se la destinazione della conversione è una classe, non sarà possibile chiamare una funzione di conversione.Tale conversione comporta la costruzione di un oggetto.Se, ad esempio, myFraction è un'istanza di CFraction che definisce l'operatore della funzione di conversione FixedPoint, la seguente espressione genererà un errore:

(FixedPoint)myFraction

Se la destinazione della conversione è un tipo incorporato, sarà tuttavia possibile chiamare una funzione di conversione.Se CFraction definisce una funzione di conversione operator float, la seguente espressione verrà considerata valida nel debugger:

(float)myFraction

È possibile chiamare le funzioni che restituiscono un oggetto o dichiarano oggetti locali.

Non è invece possibile chiamare gli operatori new e delete.La seguente espressione non funziona nel debugger:

new Date(2,3,1985)

y2t7ahxk.collapse_all(it-it,VS.110).gifEreditarietà

Quando si utilizza il debugger per visualizzare un oggetto classe che include classi base virtuali, i membri della classe base virtuale vengono visualizzati per ciascun percorso di ereditarietà, anche se ne viene memorizzata una sola istanza.

Le chiamate di funzioni virtuali vengono gestite in modo corretto nell'analizzatore di espressioni.Si supponga, ad esempio, che la classe CEmployee definisca la funzione virtuale computePay ridefinita in una classe che eredita da CEmployee.È possibile chiamare computePay tramite un puntatore a CEmployee e fare in modo che venga eseguita la funzione appropriata:

empPtr->computePay()

È possibile eseguire il cast di un puntatore a un oggetto classe derivata in un puntatore a un oggetto classe base.È possibile eseguire il cast di un puntatore a un oggetto classe base in un puntatore a un oggetto classe derivata, ad eccezione di quando l'ereditarietà è virtuale.

y2t7ahxk.collapse_all(it-it,VS.110).gifFunzioni intrinseche del compilatore e inline

Un'espressione del debugger non può chiamare un compilatore funzioni intrinseche o funzione inline a meno che venga visualizzata almeno una volta come funzione normale.

y2t7ahxk.collapse_all(it-it,VS.110).gifCostanti numeriche

Le espressioni del debugger possono utilizzare le costanti integer nel formato ottale, esadecimale o decimale.Per impostazione predefinita, il debugger prevede costanti decimali.Questa impostazione può essere modificata nella pagina Generale della scheda Debug.

Per rappresentare i numeri in un'altra base, è possibile utilizzare i simboli di prefisso o di suffisso.Nella tabella riportata di seguito sono elencati i formati utilizzabili.

Sintassi

Esempio (decimale 100)

Base

cifre

100 o 64

Decimale o esadecimale in base all'impostazione corrente

0cifre

0144

Ottale (base 8)

0ncifre

0n100

Decimale (base 10)

0xcifre

0x64

Esadecimale (base 16)

cifreh

64h

Esadecimale (base 16)

y2t7ahxk.collapse_all(it-it,VS.110).gifFunzioni degli operatori

Un'espressione del debugger può richiamare in modo implicito o esplicito le funzioni degli operatori relative a una classe.Si supponga, ad esempio, che myFraction e yourFraction siano istanze di una classe che definisce operator+.È possibile visualizzare la somma di questi due oggetti utilizzando la seguente espressione:

myFraction + yourFraction

Se la funzione di un operatore è definita come friend, è possibile chiamarla in modo implicito mediante la stessa sintassi utilizzata per una funzione membro oppure richiamarla in modo esplicito nel seguente modo:

operator+( myFraction, yourFraction )

Analogamente alle funzioni ordinarie, non è possibile chiamare le funzioni degli operatori con argomenti che richiedono una conversione che comporta la costruzione di un oggetto.

Nel debugger non sono supportati operatori di overload con entrambe le versioni const e non const.Tali operatori vengono spesso utilizzati nella Libreria di modelli standard.

y2t7ahxk.collapse_all(it-it,VS.110).gifOverload

Un'espressione del debugger può chiamare le funzioni in overload se esiste una corrispondenza esatta o se per una corrispondenza non è richiesta una conversione che comporti la costruzione di un oggetto.Se, ad esempio, la funzione calc accetta un oggetto CFraction come parametro e la classe CFraction definisce un costruttore con un singolo argomento che accetta un Integer, la seguente espressione genererà un errore:

calc( 23 )

Anche se è disponibile una conversione valida per convertire gli Integer nell'oggetto CFraction previsto da calc, questo tipo di conversione comporta la creazione di un oggetto e pertanto non è supportato.

y2t7ahxk.collapse_all(it-it,VS.110).gifPrecedenza

Nelle espressioni del debugger l'operatore di ambito C++ (::) ha una precedenza più bassa rispetto a quando si trova nel codice sorgente.Nel codice sorgente C++ tale operatore ha la precedenza più alta.Nel debugger la precedenza rientra tra gli operatori base e suffissi (->, ++, --) e gli operatori unari (!, &, * e altri).

y2t7ahxk.collapse_all(it-it,VS.110).gifFormati di simbolo

È possibile immettere un'espressione del debugger contenente dei simboli nello stesso formato utilizzato nel codice sorgente, a condizione che tali simboli si trovino in un modulo compilato con informazioni di debug complete (/Zi o /ZI).Se viene immessa un'espressione contenente simboli pubblici, ovvero simboli disponibili nelle librerie o nei moduli compilati con /Zd, è necessario utilizzare il nome decorato del simbolo, ossia il formato utilizzato nel codice oggetto.Per ulteriori informazioni, vedere /Z7, /Zd, /Zi, /ZI (Formato informazioni di debug).

Specificando l'opzione di LINK /MAP, è possibile ottenere un elenco di tutti i nomi nei formati decorati e non decorati.Per ulteriori informazioni, vedere /MAP (Genera file Map).

La decorazione dei nomi è un meccanismo utilizzato per attivare il collegamento indipendente dai tipi.Questo significa che vengono collegati solo i nomi e i riferimenti con ortografia, maiuscole/minuscole, convenzione di chiamata e tipo perfettamente corrispondenti.

I nomi dichiarati con la convenzione di chiamata C, in modo implicito o esplicito mediante la parola chiave _cdecl, iniziano con un carattere di sottolineatura (_).La funzione main può ad esempio essere visualizzata come _main.I nomi dichiarati come _fastcall iniziano con il simbolo @.

Per il linguaggio C++, il nome decorato codifica il tipo del simbolo oltre alla convenzione di chiamata.Questo formato di nome può risultare lungo e di difficile lettura.Il nome inizia con almeno un punto interrogativo (?).Per le funzioni C++, la decorazione include l'ambito della funzione, i tipi dei parametri della funzione e il tipo restituito della funzione.

y2t7ahxk.collapse_all(it-it,VS.110).gifCast di tipo

Se si esegue il cast a un tipo, è necessario che questo venga riconosciuto dal debugger.Nel programma deve essere presente un altro oggetto dello stesso tipo.I tipi creati mediante istruzioni typedef non sono supportati.