Числа и операторы C++
В этой статье описывается использование синтаксиса выражений C++ со средствами отладки Windows.
Отладчик принимает два разных типа числовых выражений: выражения C++ и выражения ассемблатора макросов Майкрософт (MASM). Каждое из этих выражений соответствует собственным правилам синтаксиса для входных и выходных данных.
Дополнительные сведения об использовании каждого типа синтаксиса см. в разделе Вычисление выражений и команда ?evaluate expression .
Средство синтаксического анализа выражений C++ поддерживает все формы синтаксиса выражений C++. Синтаксис включает все типы данных, включая указатели, числа с плавающей запятой и массивы, а также все унарные и двоичные операторы C++.
Окна Контрольные значения и Локальные в отладчике всегда используют средство оценки выражений C++.
В следующем примере команда ?? evaluate C++ expression отображает значение регистра указателя инструкции.
0:000> ?? @eip
unsigned int 0x771e1a02
Для определения размера структур можно использовать функцию C++ sizeof
.
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Задайте для вычислителя выражений значение C++
Используйте средство оценки выражений .expr, чтобы просмотреть средство оценки выражений по умолчанию и изменить его на C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
После изменения вычислителя выражений по умолчанию для отображения выражений C++ можно использовать команду ? evaluate expression . В следующем примере отображается значение регистра указателя инструкции.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Дополнительные сведения о справочнике по регистрам см. в @eip
разделе Синтаксис регистрации.
В этом примере шестнадцатеричное значение 0xD добавляется в регистр eip.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Регистры и псевдорегистры в выражениях C++
В выражениях C++ можно использовать регистры и псевдорегистры. Перед регистром или псевдорегистративом необходимо добавить знак @.
Средство оценки выражений автоматически выполняет правильное приведение. Фактические регистры и псевдорегистры целочисленных значений приведены к ULONG64
. Все адреса приведены к PUCHAR
, $thread
приводится к ETHREAD*
, приводится к , $proc
приводится к EPROCESS*
, $teb
приводится к TEB*
и $peb
приводится к PEB*
.
В этом примере отображается 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
Вы не можете изменить регистр или псевдорегистрару с помощью оператора присваивания или побочных эффектов. Для изменения этих значений необходимо использовать команду r registers .
В следующем примере псевдорегистрару присваивается значение 5, а затем отображается.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Дополнительные сведения о регистрах и псевдорегистрахах см. в разделах Синтаксис регистров и Синтаксис псевдорегистров.
Числа в выражениях C++
Числа в выражениях C++ интерпретируются как десятичные числа, если их не указать другим способом. Чтобы указать шестнадцатеричное целое число, добавьте 0x перед числом. Чтобы указать восьмеричное целое число, добавьте 0 (ноль) перед числом.
Отладчик по умолчанию не влияет на ввод выражений C++. Вы не можете напрямую ввести двоичное число, кроме как путем вложения выражения MASM в выражение C++.
Можно ввести шестнадцатеричное 64-разрядное значение в формате xxxxxxxx'xxxxxxxx. Можно также опустить серьезный акцент ('). Оба формата дают одинаковое значение.
Можно использовать суффиксы L
, U
и I64
с целочисленными значениями. Фактический размер создаваемого числа зависит от суффикса и введенного числа. Дополнительные сведения об этой интерпретации см. в справочнике по языку C++.
Выходные данные средства оценки выражений C++ сохраняют тип данных, заданный правилами выражений C++. Однако при использовании этого выражения в качестве аргумента для команды всегда выполняется приведение. Например, вам не нужно приводить целочисленные значения к указателям, если они используются в качестве адресов в аргументах команды. Если значение выражения не может быть правильно приведено к целочислению или указателю, возникает синтаксическая ошибка.
Для некоторых выходных0n
данных можно использовать префикс (decimal), но нельзя использовать его для входных данных выражений C++.
Символы и строки в выражениях C++
Можно ввести символ, заключив его в одинарные кавычки ('). Разрешены стандартные escape-символы C++.
Можно ввести строковые литералы, заключив их в двойные кавычки ("). Вы можете использовать \" в качестве escape-последовательности в такой строке. Однако строки не имеют значения для вычислителя выражений.
Символы в выражениях C++
В выражении C++ каждый символ интерпретируется в соответствии с его типом. В зависимости от того, на что ссылается символ, он может интерпретироваться как целое число, структура данных, указатель функции или любой другой тип данных. Синтаксическая ошибка возникает, если в выражении C++ используется символ, не соответствующий типу данных C++, например имя неизмененного модуля.
В имени символа можно использовать гравейную диакритику (') или апостроф (') только в том случае, если перед именем символа вы добавите имя модуля и восклицательный знак. При добавлении < разделителей и > после имени шаблона можно добавлять пробелы между ними.
Если символ может быть неоднозначным, можно добавить имя модуля и восклицательный знак (!) или только восклицательный знак перед символом. Чтобы указать, что символ должен быть локальным, опустите имя модуля и добавьте знак доллара и восклицательный знак ($!) перед именем символа. Дополнительные сведения о распознавании символов см. в разделе Синтаксис символов и сопоставление символов.
Структуры в выражениях C++
Средство оценки выражений C++ приводит псевдорегистры к соответствующим типам. Например, $teb
приводится как 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
В следующем примере в структуре TEB отображается идентификатор процесса, показывающий использование указателя на элемент структуры, на который указывает ссылка.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Операторы в выражениях C++
Для переопределения правил приоритета можно использовать круглые скобки.
Если заключить часть выражения C++ в круглые скобки и добавить два знака (@@) перед выражением, выражение интерпретируется в соответствии с правилами выражений MASM. Нельзя добавить пробел между двумя знаками и открывающей скобкой. Окончательное значение этого выражения передается в средство оценки выражений C++ в качестве значения ULONG64. Вы также можете указать вычислитель выражений с помощью @@c++( ... )
или @@masm( ... )
.
На языке C++ типы данных обозначаются как обычные. Распознаются символы, указывающие массивы ([ ]), элементы указателя (->), элементы определяемого пользователем типа (.) и члены классов (::). Поддерживаются все арифметические операторы, включая операторы присваивания и побочных эффектов. Однако нельзя использовать операторы new
, delete
и , а throw
также нельзя вызывать функцию.
Поддерживается арифметика указателей, а смещения масштабируются правильно. Обратите внимание, что вы не можете добавить смещение к указателю функции. Если необходимо добавить смещение к указателю функции, сначала приведите смещение к указателю символа.
Как и в C++, при использовании операторов с недопустимыми типами данных возникает синтаксическая ошибка. Средство синтаксического анализа выражений C++ в отладчике использует несколько более строгие правила, чем большинство компиляторов C++, но применяются все основные правила. Например, нельзя сместить не целочисленное значение.
Можно использовать следующие операторы. Операторы в каждой ячейке имеют приоритет над операторами в нижних ячейках. Операторы в одной ячейке имеют одинаковый приоритет и анализируются слева направо.
Как и в случае с C++, вычисление выражений заканчивается, когда известно его значение. Это окончание позволяет эффективно использовать такие выражения, как ?? myPtr && *myPtr
.
Приведение ссылок и типов
Оператор | Значение |
---|---|
Выражение // Комментарий | Пропустить весь последующий текст |
Класс :: Член | Член класса |
Класс ::~Member | Член класса (деструктор) |
:: Имя | Глобальный |
Структура . Поле | Поле в структуре |
Указатель ->Поле | Поле в структуре, на который указывает ссылка |
Имя [целое число] | Индекс массива |
Lvalue ++ | Приращение (после оценки) |
Lvalue -- | Уменьшение (после оценки) |
Dynamic_cast<Тип>(Значение) | Typecast (всегда выполняется) |
Static_cast<Тип>(Значение) | Typecast (всегда выполняется) |
Reinterpret_cast<Тип>(Значение) | Typecast (всегда выполняется) |
< const_castТип>(Значение) | Typecast (всегда выполняется) |
Операции со значениями
Оператор | Значение |
---|---|
(тип) Значение | Typecast (всегда выполняется) |
sizeofvalue | Размер выражения |
sizeof( тип ) | Размер типа данных |
++ Lvalue | Приращение (до оценки) |
-- Lvalue | Уменьшение (до оценки) |
~ Значение | Битовое дополнение |
! Значение | Not (boolean) |
Значение | Унарный минус |
+ Значение | Унарный плюс |
& LValue | Адрес типа данных |
Значение | Dereference |
Структура . Указатель | Указатель на элемент структуры |
Указатель —> * Указатель | Указатель на элемент структуры, на который указывает ссылка |
Арифметический
Оператор | Значение |
---|---|
Значение | Умножение |
Значение / Значение | Отдел |
Значение % Значение | Модуль |
Значение + Значение | Сложение |
Значение - Значение | Вычитание |
Значение<<Значение | Побитовое смещение влево |
Значение>>Значение | Побитовое смещение вправо |
Значение<Значение | Меньше (сравнение) |
Значение<= значение | Меньше или равно (сравнение) |
Значение>Значение | Больше (сравнение) |
Значение>= значение | Больше или равно (сравнение) |
Значение == Значение | Равно (сравнение) |
Значение != значение | Не равно (сравнение) |
Значение & Значение | Побитовое И |
Значение ^ Значение | Побитовое XOR (исключающее ИЛИ) |
Значение | Значение | Побитовое ИЛИ |
Значение && Значение | Логическое И |
Значение || Значение | Логическое ИЛИ |
В следующих примерах предполагается, что псевдорегистры заданы, как показано ниже.
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
Назначение
Оператор | Значение |
---|---|
Lvalue = Значение | Присвоение |
Lvalue *= Значение | Умножение и назначение |
Lvalue /= Значение | Деление и присваивание |
Lvalue %= Значение | Остаток от деления и присваивание |
Lvalue += Значение | Сложение и присваивание |
Lvalue -= Значение | Вычитание и присваивание |
Lvalue<<= значение | Сдвиг влево и назначение |
Lvalue>>= значение | Сдвиг вправо и назначение |
LValue &= Значение | И и назначение |
Lvalue |= Значение | ИЛИ и назначение |
Lvalue ^= Значение | XOR и назначение |
Ознакомительная версия
Оператор | Значение |
---|---|
Значение ? Значение : значение | Условная оценка: |
Значение , значение | Оценка всех значений, а затем удаление всех значений, кроме крайнего правого значения |
Макросы в выражениях C++
Макросы можно использовать в выражениях C++. Перед макросами необходимо добавить знак числа (#).
Вы можете использовать следующие макросы. Эти макросы имеют те же определения, что и макросы Microsoft Windows с тем же именем. Макросы Windows определяются в Winnt.h
.
Макрос | Возвращаемое значение |
---|---|
#CONTAINING_RECORD(Адрес, Тип, Поле) | Возвращает базовый адрес экземпляра структуры с учетом типа структуры и адреса поля в структуре. |
#FIELD_OFFSET(Тип, Поле) | Возвращает смещение в байтах именованного поля в известном типе структуры. |
#RTL_CONTAINS_FIELD(Struct, Size, Field) | Указывает, включает ли заданный размер байта нужное поле. |
#RTL_FIELD_SIZE(Тип, Поле) | Возвращает размер поля в структуре известного типа, не требуя тип поля. |
#RTL_NUMBER_OF(Array) | Возвращает количество элементов в массиве статических размеров. |
#RTL_SIZEOF_THROUGH_FIELD(Тип, Поле) | Возвращает размер структуры известного типа, вплоть до указанного поля. |
В этом примере показано использование макроса #FIELD_OFFSET
для вычисления смещения байтов к полю в структуре.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
См. также раздел
Выражения MASM и выражения C++
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по