Compartir a través de


Expresiones en C++ nativo

El depurador acepta la mayoría de las expresiones de Microsoft y ANSI C/C++. El depurador también proporciona funciones intrínsecas y operadores de contexto para crear expresiones de evaluación más seguras y adecuadas. En este tema también se describen las restricciones de las expresiones de C++ que deben tener en cuenta lo siguiente:

No se puede utilizar el operador de contexto ni la mayoría de los especificadores de formato en el código, script o expresiones de código administrado. Son específicos del evaluador de expresiones de C++ nativo.

En esta sección

Usar funciones intrínsecas del depurador para mantener el estado

Usar operadores de contexto para especificar un símbolo

Restricciones de las expresiones de C++ nativo

  • Control de acceso

  • Referencias ambiguas

  • Espacios de nombres anónimos

  • Constructores, destructores y conversiones

  • Herencia

  • Funciones insertadas e intrínsecas de compilador

  • Constantes numéricas

  • Funciones de operador

  • Sobrecarga

  • Precedencia

  • Formatos de símbolos

  • Conversión de tipos

Usar funciones intrínsecas del depurador para mantener el estado

Las funciones intrínsecas del depurador proporcionan una manera de llamar a determinadas funciones de C/C++ en expresiones sin cambiar el estado de la aplicación.

Funciones intrínsecas del depurador:

  • Se garantiza que son seguras: ejecutar una función intrínseca del depurador no dañará el proceso que se está depurando.

  • Se permiten en todas las expresiones, incluso en escenarios en los que no se permiten efectos secundarios ni evaluación de funciones.

  • Funcionan en escenarios en los que no son posibles llamadas de función estándar, por ejemplo la depuración de un minivolcado.

Las funciones intrínsecas del depurador también pueden crear expresiones de evaluación más adecuadas. Por ejemplo, strncmp(str, “asd”) es mucho más fácil de escribir en una condición de punto de interrupción que str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’. )

Área

Funciones intrínsecas

Longitud de la cadena

strlen, wcslen, strnlen, wcsnlen

Comparación de cadena

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

Búsqueda de cadena

strchr, wcschr, strstr, wcsstr

Win32

GetLastError(), TlsGetValue()

Windows 8

WindowsGetStringLen(), WindowsGetStringRawBuffer()

Estas funciones requieren el proceso que se depura para ejecutarse en Windows 8. La depuración de archivos de volcado de memoria generados por un dispositivo con Windows 8 también requiere que el equipo de Visual Studio ejecute Windows 8. Sin embargo, si depura un dispositivo con Windows 8 de forma remota, el equipo de Visual Studio puede ejecutar Windows 7.

Varios

__log2

Devuelve el logaritmo en base dos de un entero especificado, redondeado al entero más bajo más próximo.

Usar operadores de contexto para especificar un símbolo

El operador de contexto es un operador adicional que proporciona el depurador nativo. Al depurar código nativo, puede utilizar el operador de contexto para calificar una ubicación de punto de interrupción, nombre de variable o expresión. El operador de contexto resulta útil, por ejemplo, para especificar un nombre desde un ámbito externo que se encuentra oculto por un nombre local.

Sintaxis

{,,[module] } expression

  • module es el nombre de un módulo. Puede utilizar una ruta de acceso completa para eliminar la ambigüedad entre módulos con el mismo nombre.

  • expression es cualquier expresión de C++ válida que se resuelve en un destino válido, por ejemplo un nombre de función, nombre de variable o dirección del puntero de module.

Las llaves deben contener dos comas y el nombre o la ruta de acceso completa del módulo (archivo ejecutable o DLL).

Por ejemplo, para establecer un punto de interrupción en la función de SomeFunction de EXAMPLE.dll:

{,,EXAMPLE.dll}SomeFunction

Si la ruta de acceso de module incluye una coma, un espacio incrustado o una llave, debe encerrar el nombre de la ruta de acceso entre comillas para que el analizador de contexto pueda reconocer correctamente la cadena. Las comillas simples se consideran parte de un nombre de archivo de Windows, por lo que deben utilizarse comillas dobles. Por ejemplo,

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

Cuando el evaluador de expresiones encuentra un símbolo en una expresión, busca el símbolo en el siguiente orden:

  1. Salida del ámbito léxico, empezando por el bloque actual, la serie de instrucciones entre llaves y continuando la salida con el bloque de inclusión. El bloque actual es el código que contiene la ubicación actual, la dirección del puntero de instrucción.

  2. Ámbito de función. La función actual.

  3. Ámbito de clase, si la ubicación actual está dentro de una función miembro de C++. El ámbito de clase incluye todas las clases base. El evaluador de expresiones utiliza las reglas de dominación normales.

  4. Símbolos globales del módulo actual.

  5. Símbolos públicos del programa actual.

Con el operador de contexto se especifica el módulo inicial de la búsqueda y se omite la posición actual.

Restricciones de las expresiones de C++ nativo

Cuando se escribe una expresión de C/C++ en una ventana del depurador, se aplican las siguientes restricciones generales:

Control de acceso

El depurador puede tener acceso a todos los miembros de clase, con independencia del control de acceso. Puede examinar cualquier miembro del objeto de clase, incluidas las clases base y los objetos de miembros incrustados.

Referencias ambiguas

Si una expresión de depurador hace referencia a un nombre de miembro ambiguo, debe utilizar el nombre de clase para calificarlo. Por ejemplo, si CObject es una instancia de CClass, que hereda funciones miembro denominadas expense tanto de AClass como de BClass, CObject.expense es ambigua. Puede resolver la ambigüedad de esta forma:

CObject.BClass::expense

Para resolver ambigüedades, el evaluador de expresiones aplica reglas de dominación normales relativas a los nombres de miembro.

Espacios de nombres anónimos

El evaluador de expresiones de C++ nativo no admite espacios de nombres anónimos. Suponga, por ejemplo, que tiene el código siguiente:

#include "stdafx.h"

namespace mars 
{ 
    namespace
    {
        int test = 0; 
    } 

} 


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

La única manera de ver el símbolo test en este ejemplo es utilizar el nombre representativo:

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

Constructores, destructores y conversiones

No se puede llamar a un constructor o destructor de un objeto, ya sea explícita o implícitamente, mediante una expresión que requiere la construcción de un objeto temporal. Por ejemplo, la siguiente expresión llama explícitamente a un constructor y se produce un mensaje de error:

Date( 2, 3, 1985 )

No se puede llamar a una función de conversión si el destino de la conversión es una clase. Dicha conversión implica la construcción de un objeto. Por ejemplo, si myFraction es una instancia de CFraction, que define el operador de la función de conversión FixedPoint, la siguiente expresión genera un error:

(FixedPoint)myFraction

No obstante, puede llamar a una función de conversión si el destino de la conversión es un tipo integrado. Si CFraction define una función de conversión operator float, la siguiente expresión es válida en el depurador:

(float)myFraction

Puede llamar a funciones que devuelven un objeto o declarar objetos locales.

No puede llamar a los operadores new o delete. La siguiente expresión no funciona en el depurador:

new Date(2,3,1985)

Herencia

Cuando se utiliza el depurador para mostrar un objeto de clase que tiene clases base virtuales, los miembros de estas se muestran para cada ruta de acceso de herencia, si bien solo se almacena una instancia de dichos miembros.

El evaluador de expresiones controla correctamente las llamadas a funciones virtuales. Por ejemplo, suponga que la clase CEmployee define una función virtual computePay, que se vuelve a definir en una clase que hereda de CEmployee. Puede llamar a computePay mediante un puntero a CEmployee y hacer que se ejecute la función apropiada:

empPtr->computePay()

Puede convertir un puntero a un objeto de clase derivada en un puntero a un objeto de clase base. Puede convertir un puntero a un objeto de clase base en un puntero a un objeto de clase derivada, excepto si la herencia es virtual.

Funciones insertadas e intrínsecas de compilador

Una expresión de depurador no puede llamar a funciones insertadas o intrínsecas de compilador, a no ser que aparezcan como funciones normales al menos una vez.

Constantes numéricas

Las expresiones de depurador pueden utilizar constantes enteras en formato octal, hexadecimal o decimal. De forma predeterminada, el depurador espera constantes decimales. Esta configuración se puede cambiar en la página General de la ficha Depuración.

Puede utilizar símbolos de prefijo o sufijo para representar números en otra base. En la siguiente tabla se muestran los formatos que se pueden utilizar.

Sintaxis

Ejemplo (decimal 100)

Base

digits

100 ó 64

Decimal o hexadecimal, en función de la configuración actual.

0 digits

0144

Octal (base 8)

0n digits

0n100

Decimal (base 10)

0x digits

0x64

Hexadecimal (base 16)

digits h

64h

Hexadecimal (base 16)

Funciones de operador

Una expresión de depurador puede invocar implícita o explícitamente funciones de operador para una clase. Por ejemplo, suponga que myFraction y yourFraction son instancias de una clase que define operator+. Puede mostrar la suma de esos dos objetos mediante la siguiente expresión:

myFraction + yourFraction

Si una función de operador se define como friend, se puede llamar implícitamente mediante la misma sintaxis que se utilizaría para una función miembro, o puede invocarla explícitamente como se muestra a continuación:

operator+( myFraction, yourFraction )

Al igual que las funciones normales, a las funciones de operador no se las puede llamar con argumentos que requieran una conversión que implique la construcción de objetos.

El depurador no admite operadores sobrecargados con versiones constantes y no constantes. Los operadores sobrecargados con versiones constantes y no constantes se utilizan con frecuencia en la Biblioteca de plantillas estándar.

Sobrecarga

Una expresión de depurador puede llamar a funciones sobrecargadas si existe una coincidencia exacta, o si una coincidencia no requiere una conversión que implique la construcción de objetos. Por ejemplo, si la función calc toma un objeto CFraction como parámetro y la clase CFraction define un constructor de un único argumento que acepta un entero, la siguiente expresión genera un error:

calc( 23 )

Aunque existe una conversión válida para convertir el entero en el objeto CFraction que espera calc, dicha conversión requiere la creación de un objeto y no se permite.

Precedencia

En las expresiones de depurador, el operador de ámbito de C++ (::) tiene menor prioridad que en el código fuente. En código fuente de C++, este operador tiene la mayor prioridad. En el depurador, su prioridad se sitúa entre la de los operadores de base y de postfijo (->, ++, --) y la de los operadores unarios (!, &, *, y otros).

Formatos de símbolos

Una expresión de depurador que contiene símbolos se escribe de la misma forma que en el código fuente, siempre que los símbolos estén en un módulo compilado con toda la información de depuración (/Zi o /ZI). Si escribe una expresión que contiene símbolos públicos, que se encuentran en bibliotecas o en módulos compilados con /Zd, debe utilizar el nombre representativo del símbolo (el formato que se utiliza en el código objeto). Para obtener más información, vea /Z7, /Zd, /Zi, /ZI (Formato de la información de depuración).

Puede obtener una lista de todos los nombres en formato representativo y no representativo mediante la opción LINK /MAP. Para obtener más información, vea /MAP (Generar archivo de asignaciones).

La creación de nombres representativos es el mecanismo que se utiliza para exigir vinculaciones con seguridad de tipos. Esto significa que solo se vinculan los nombres y referencias cuya ortografía, mayúsculas y minúsculas, convención de llamada y tipo coincidan exactamente.

Los nombres que se declaran con la convención de llamada de C, ya sea implícita o explícitamente mediante la palabra clave _cdecl, comienzan con un carácter de subrayado (_). Por ejemplo, la función main puede mostrarse como _main. Los nombres declarados como _fastcall comienzan con el símbolo @.

Para C++, el nombre representativo codifica el tipo del símbolo además de la convención de llamada. Este formato del nombre puede resultar largo y difícil de leer. El nombre comienza con, al menos, un signo de interrogación (?). Para las funciones de C++, la creación de nombres representativos incluye el ámbito de la función, los tipos de los parámetros de la función y el tipo de valor devuelto de la función.

Conversión de tipos

Si se convierte a un tipo, lo debe conocer el depurador. Se debe tener otro objeto de ese tipo en el programa. No se admiten tipos creados mediante instrucciones typedef.