Выражения в машинном коде C++
Отладчик принимает большинство выражений Microsoft C/C++ и ANSI C/C++. Отладчик также предоставляет встроенные функции и операторы контекста, благодаря которым вычисление выражений становится более безопасным и более удобным. В этом разделе также описаны ограничения на выражения C++, которые следует учитывать в связи со следующими особенностями:
Оператор контекста и большая часть описателей формата не могут использоваться в коде и в выражениях скрипта или управляемого кода. Они определены только для вычислителя выражения машинного C++.
В данном разделе
Использование встроенных функций отладчика для сохранения состояния
Использование операторов контекста для указания символа
Ограничения на выражения C++ в машинном коде
Управление доступом
Неоднозначные ссылки
Анонимные пространства имен
Конструкторы, деструкторы и преобразования
Наследование
Подставляемые функции и встроенные функции компилятора
Числовые константы
Функции оператора
Перегрузка
Приоритет
Форматы символов
Приведение типа
Использование встроенных функций отладчика для сохранения состояния
С помощью встроенных функций отладчика можно вызывать некоторые функции C/C++ в выражениях, не изменяя при этом состояние приложения.
Встроенные функции отладчика:
Гарантированно безопасны: выполнение встроенной функции отладчика не приведет к повреждению отлаживаемого процесса.
Могут использоваться в любых выражениях, в том числе в сценариях, не допускающих побочные эффекты и вычисление функций.
Работают в сценариях, в которых обычные вызовы функций невозможны, как, например, при отладке минидампа.
Кроме того, встроенные функции отладчика могут сделать вычисление выражений более удобным. Например, в качестве условия останова намного удобнее использовать выражение вида strncmp(str, “asd”), чем выражение str[0] == ‘a’ && str[1] == ‘s’ && str[2] == ‘d’. )
Область |
Встроенные функции |
---|---|
Длина строки |
strlen, wcslen, strnlen, wcsnlen |
Сравнение строк |
strcmp, wcscmp, stricmp, _stricmp, _strcmpi, wcsicmp, _wcscmpi, _wcsnicmp, strncmp, wcsncmp, strnicmp, wcsnicmp |
Поиск строки |
strchr, wcschr, strstr, wcsstr |
Win32 |
GetLastError(), TlsGetValue() |
Windows 8 |
WindowsGetStringLen(), WindowsGetStringRawBuffer() Для этих функций требуется, чтобы отлаживаемый процесс выполнялся в Windows 8. Для отладки файлов дампа, сгенерированных устройством Windows 8, также необходимо, чтобы компьютер Visual Studio работал под управлением Windows 8. В то же время, если устройство Windows 8 отлаживается удаленно, допускается работа компьютера Visual Studio под управлением Windows 7. |
Прочее |
__log2 Возвращает значение логарифма по основанию 2 от указанного целого числа, округленное до ближайшего меньшего целого числа. |
Использование операторов контекста для указания символа
Оператор контекста — это дополнительный оператор, предоставляемый отладчиком машинного кода. Этот оператор можно использовать при отладке машинного кода для уточнения имени переменной, выражения или расположения точки останова. С помощью оператора контекста можно, например, указать имя из внешней области, чтобы это имя не оказалось перекрыто локальным именем.
Синтаксис
{,,[module] } expression
module — имя модуля. В имени модуля можно указывать полный путь во избежание неоднозначности указания модулей с одинаковыми именами.
expression — любое допустимое выражение C++, результатом которого является допустимый целевой объект (например, имя функции, имя переменной или адрес указателя) в module.
Фигурные скобки должны содержать две запятые и имя либо полный путь к модулю (исполняемому файлу или DLL-файлу).
Пример синтаксиса для установки точки останова на функции SomeFunction в файле EXAMPLE.dll:
{,,EXAMPLE.dll}SomeFunction
Если путь к module содержит запятую, внутренний пробел или фигурную скобку, такой путь необходимо заключить в кавычки, чтобы средство синтаксического анализа контекста смогло правильно распознать строку. Одинарные кавычки воспринимаются как часть имени файла Windows, поэтому для этой цели должны использоваться двойные кавычки. Например:
{,"a long, long, library name.dll", } g_Var
Когда вычислитель выражений встречает в выражении символ, он ищет его в следующем порядке:
В лексической области и за ее пределами, начиная с текущего блока (последовательности операторов, заключенной в фигурные скобки) и затем переходя к внешнему блоку, содержащему текущий. Текущий блок — это код, содержащий текущее расположение, адрес указателя инструкции.
Область видимости функции. Текущая функция.
В области видимости класса, если текущее расположение находится внутри функции-члена языка C++. Область видимости класса включает все базовые классы. Вычислитель выражений использует обычные правила доминирования.
Глобальные символы в текущем модуле.
Открытые символы в текущей программе.
С помощью оператора контекста задается начальный модуль для поиска и обходится текущее расположение.
Ограничения на выражения C++ в машинном коде
При вводе выражения на языке C/C++ в окне отладчика применимы перечисленные ниже общие ограничения.
Управление доступом
Отладчик может получать доступ ко всем членам класса независимо от настройки управления доступом. Можно проверить любой член объекта класса, включая базовые классы и внедренные объекты-члены.
Неоднозначные ссылки
Если выражение отладчика ссылается на неоднозначное имя члена, имя следует уточнить с помощью имени класса. Например, если объект CObject является экземпляром класса CClass, который наследует функции члена с именем expense из классов AClass и BClass, то имя CObject.expense будет неоднозначным. Эту неоднозначность можно устранить путем следующего уточнения:
CObject.BClass::expense
Для устранения неоднозначностей вычислитель выражений применяет по отношению к именам членов обычные правила доминирования.
Анонимные пространства имен
Вычислитель выражений в машинном коде C++ не поддерживает анонимные пространства имен. Предположим, например, что имеется следующий код:
#include "stdafx.h"
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
Единственный способ наблюдать символ test в этом примере состоит в использовании декорированного имени:
(int*)?test@?A0xccd06570@mars@@3HA
Конструкторы, деструкторы и преобразования
Конструктор или деструктор объекта невозможно вызвать (ни явным, ни неявным образом) с помощью выражения, требующего создания временного объекта. Например, следующее выражение вызывает конструктор явным способом, что приводит к сообщению об ошибке:
Date( 2, 3, 1985 )
Функция преобразования не может быть вызвана, если результатом преобразования является класс. Такое преобразование включает создание объекта. Например, если myFraction — экземпляр класса CFraction, в котором определен оператор функции преобразования FixedPoint, то следующее выражение вызовет ошибку:
(FixedPoint)myFraction
Однако вызов функции преобразования допускается, если результатом преобразования является встроенный тип. Если класс CFraction определяет функцию преобразования operator float, то следующее выражение в отладчике является допустимым:
(float)myFraction
Разрешен вызов функций, возвращающих объект или объявляющих локальные объекты.
Не допускается вызов операторов new или delete. Следующее выражение в отладчике работать не будет:
new Date(2,3,1985)
Наследование
При использовании отладчика для отображения объекта класса, в котором имеются виртуальные базовые классы, члены виртуального базового класса отображаются по каждому из путей наследования, даже если сохранен только один экземпляр таких членов.
Вычислитель выражений надлежащим образом обрабатывает вызовы виртуальной функции. Предположим, например, что класс CEmployee определяет виртуальную функцию computePay, которая переопределяется в классе, наследующем из класса CEmployee. Функцию computePay можно вызвать через указатель на класс CEmployee, и она будет выполнена надлежащим образом:
empPtr->computePay()
Указатель на объект производного класса можно привести к указателю на объект базового класса. Указатель на объект базового класса можно привести к указателю на объект производного класса, если только наследование не является виртуальным.
Подставляемые функции и встроенные функции компилятора
Выражение отладчика не может вызывать встроенные функции компилятора или подставляемые функции, если такая функция не указана хотя бы однажды как обычная функция.
Числовые константы
В выражениях отладчика допускается использовать целочисленные константы в восьмеричном, шестнадцатеричном или десятичном формате. По умолчанию отладчик ожидает ввода десятичных констант. Этот параметр можно изменить на странице Общие вкладки Отладка.
Для представления чисел в другой системе счисления можно использовать символы префикса или суффикса. В следующей таблице показаны допустимые форматы.
Синтаксис |
Пример (десятичное число 100) |
Базовый |
---|---|---|
digits |
100 или 64 |
10 или 16, в зависимости от текущей настройки. |
0 digits |
0144 |
8 (основание 8) |
0n digits |
0n100 |
10 (основание 10) |
0x digits |
0x64 |
16 (основание 16) |
digits h |
64h |
16 (основание 16) |
Функции оператора
Выражение отладчика может явным или неявным образом вызывать функции оператора для класса. Предположим, например, что myFraction и yourFraction являются экземплярами класса, в котором определена функция operator+. С помощью следующего выражения можно получить сумму этих двух объектов:
myFraction + yourFraction
Если функция оператора определена как дружественная, ее можно вызвать неявно, используя такой же синтаксис, как и для функции-члена, или же вызвать ее явным способом, как показано в следующем примере:
operator+( myFraction, yourFraction )
Функции оператора, как и обычные функции, не могут вызываться с аргументами, требующими преобразования с созданием объекта.
Отладчик не поддерживает перегруженные операторы, имеющие как константную, так и неконстантную версии. Перегруженные операторы с константной и неконстантной версиями часто используются в Библиотеке стандартных шаблонов.
Перегрузка
Выражение отладчика может вызывать перегруженные функции, если имеет место точное соответствие или соответствие не требует преобразования с созданием объекта. Например, если функция calc принимает объект CFraction в качестве параметра, а в классе CFraction определен конструктор с одним аргументом, принимающий на вход целое число, то следующее выражение вызовет ошибку:
calc( 23 )
Несмотря на то, что существует допустимое преобразование целого числа в объект CFraction, ожидаемый функцией calc, такое преобразование требует создания объекта и поэтому не поддерживается.
Приоритет
Оператор области видимости языка C++ (::) в выражениях отладчика имеет более низкий приоритет по сравнению с его приоритетом в исходном коде. В исходном коде на языке C++ этот оператор обладает наивысшим приоритетом с точки зрения очередности применения. В отладчике же его приоритет применения выше, чем у базовых и постфиксных операторов (->, ++, --), но ниже, чем у унарных операторов (!, &, * и др.).
Форматы символов
Выражение с символами вводится в отладчике в том же виде, который используется в исходном коде, при условии что символы находятся в модуле, который был скомпилирован в режиме вывода полных отладочных данных (/Zi или /ZI). Если вводится выражение с открытыми символами, которые находятся в библиотеках или в модулях, скомпилированных с параметром /Zd, необходимо использовать декорированное имя символа (форму, используемую в объектном коде). Дополнительные сведения см. в разделе /Z7, /Zd, /Zi, /ZI (формат отладочной информации).
Список всех имен в декорированной и недекорированной формах можно получить с помощью параметра LINK /MAP. Дополнительные сведения см. в разделе /MAP (Создание файла сопоставления).
Декорирование имен — это механизм, применяемый для обеспечения типобезопасной компоновки. При такой компоновке связываются только имена и ссылки, у которых точно совпадает написание, регистр, соглашение о вызовах и тип.
Имена, объявленные с использованием соглашения о вызовах языка C (неявным образом или явным с помощью ключевого слова _cdecl), начинаются со знака подчеркивания (_). Например, функция main может отображаться как _main. Имена, объявленные как _fastcall, начинаются со знака @.
В C++ в декорированном имени, помимо соглашения о вызовах, кодируется тип символа. Такая форма имени может оказаться длинной и сложной для чтения. Имя начинается как минимум с одного вопросительного знака (?). В функциях C++ декорирование включает в себя область видимости функции, типы параметров функции и тип возвращаемого функцией значения.
Приведение типа
При выполнении приведения к типу необходимо, чтобы этот тип был известен отладчику. В программе должен быть еще один объект того же типа. Типы, созданные с помощью операторов typedef, не поддерживаются.