Номера и операторы C++
В этой статье описывается использование синтаксиса выражений C++ с средствами отладки Windows.
Отладчик принимает два различных типа числовых выражений: выражения C++ и выражения сборщика макросов Майкрософт (MASM). Каждое из этих выражений соответствует собственным правилам синтаксиса входных и выходных данных.
Дополнительные сведения об использовании каждого типа синтаксиса см. в статье "Оценка выражений " и команда "Оценить выражение ".
Средство синтаксического анализа выражений C++ поддерживает все формы синтаксиса выражений C++. Синтаксис включает все типы данных, включая указатели, числа с плавающей запятой и массивы, а также все унарные и двоичные операторы C++.
Окна "Контрольные " и "Локальные" в отладчике всегда используют средство оценки выражений C++.
В следующем примере команда выражения ?? вычисляет выражение C++ отображает значение регистра указателя инструкции.
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++. В следующем примере отображается значение регистра указателя инструкции.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Дополнительные сведения о ссылке @eip
на регистрацию см. в разделе "Регистрация синтаксиса".
В этом примере шестнадцатеричное значение 0xD добавляется в регистр eip.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Регистры и псевдорегистры в выражениях C++
В выражениях C++ можно использовать регистры и псевдорегистры. Перед регистрацией или псевдорегистром необходимо добавить знак @.
Средство оценки выражений автоматически выполняет правильный приведение. Фактические регистры и псевдорегистры целочисленного значения приведение ULONG64
к . Все адреса приведениеPUCHAR
ETHREAD*
$thread
, приведение к, приведение к, $proc
приведение к, приведение EPROCESS*
к, $teb
и $peb
приведение TEB*
к.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
Дополнительные сведения о регистрах и псевдорегистрирующих регистрах см. в разделе Register синтаксис и синтаксис псевдорегистрирующего регистра.
Числа в выражениях C++
Числа в выражениях C++ интерпретируются как десятичные числа, если они не указаны другим способом. Чтобы указать шестнадцатеричное целое число, добавьте 0x перед числом. Чтобы указать восьмеричное целое число, добавьте 0 (ноль) перед числом.
Радикс отладчика по умолчанию не влияет на способ ввода выражений C++. Вы не можете напрямую ввести двоичное число, за исключением вложенного выражения MASM в выражение C++.
Шестнадцатеричное 64-разрядное значение можно ввести в формате xxxx'xxxx. Вы также можете опустить серьезный акцент ('). Оба формата создают одно и то же значение.
Можно использовать L
суффиксы и U
I64
суффиксы со целыми значениями. Фактический размер создаваемого числа зависит от суффикса и введенного числа. Дополнительные сведения об этой интерпретации см. в справочнике по языку C++.
Выходные данные вычислителя выражений C++ сохраняют тип данных, указанный правилами выражений C++. Однако при использовании этого выражения в качестве аргумента для команды всегда выполняется приведение. Например, вам не нужно приведение целых значений к указателям, когда они используются в качестве адресов в аргументах команд. Если значение выражения не может быть допустимо приведение к целочислению или указателю, возникает синтаксическая ошибка.
Префикс (десятичный) можно использовать 0n
для некоторых выходных данных, но его нельзя использовать для ввода выражений 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++. Символы, указывающие массивы ([ ]), элементы указателя (->), элементы UDT (.) и члены классов (::) распознаются. Поддерживаются все арифметические операторы, включая операторы назначения и побочных эффектов. Однако вы не можете использовать new
операторы и delete
throw
операторы, и вы не можете на самом деле вызвать функцию.
Арифметика указателя поддерживается и смещения масштабируются правильно. Обратите внимание, что невозможно добавить смещение в указатель функции. Если необходимо добавить смещение в указатель функции, сначала приведите смещение к указателю символа.
Как и в C++, при использовании операторов с недопустимыми типами данных возникает синтаксическая ошибка. Средство синтаксического анализа выражений C++ отладчика использует немного более расслабленные правила, чем большинство компиляторов C++, но все основные правила применяются. Например, нельзя изменить целочисленное значение.
Можно использовать следующие операторы. Операторы в каждой ячейке имеют приоритет над операторами в нижних ячейках. Операторы в одной ячейке имеют одинаковый приоритет и анализируются слева направо.
Как и в C++, оценка выражений заканчивается, когда его значение известно. Это окончание позволяет эффективно использовать такие выражения, как ?? myPtr && *myPtr
.
Приведение ссылок и типов
Оператор | Значение |
---|---|
Комментарий выражения // | Игнорировать весь последующий текст |
Класс :: Член | Член класса |
Класс ::~Member | Член класса (деструктор) |
:: Имя | Глобальный |
Структура. Поле | Поле в структуре |
Указатель ->Поле | Поле в указанной структуре |
Имя [целое число] | Индекс массива |
LValue ++ | Добавочный (после оценки) |
LValue -- | Декремент (после оценки) |
<dynamic_cast type>(Value) | Typecast (всегда выполняется) |
<тип> static_cast(Значение) | Typecast (всегда выполняется) |
<reinterpret_cast type>(Value) | Typecast (всегда выполняется) |
<тип> const_cast(значение) | Typecast (всегда выполняется) |
Операции со значением
Оператор | Значение |
---|---|
(тип) Значение | Typecast (всегда выполняется) |
значение sizeof | Размер выражения |
sizeof( тип ) | Размер типа данных |
++ LValue | Добавочный (перед оценкой) |
-- LValue | Декремент (перед оценкой) |
~ Value | Битовое дополнение |
! Value | Not (Boolean) |
Value | Унарный минус |
+ Value | Унарный плюс |
& LValue | Адрес типа данных |
Value | 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 &= Value | И и назначение |
Значение LValue |= | ИЛИ и назначение |
Значение LValue ^= | XOR и назначение |
Оценка
Оператор | Значение |
---|---|
Значение ? Значение: значение | Условная оценка: |
Значение, значение | Оценка всех значений, а затем отмена всех, кроме самого правого значения |
Макросы в выражениях C++
Макросы можно использовать в выражениях C++. Перед макросами необходимо добавить знак номера (#).
Можно использовать следующие макросы. Эти макросы имеют те же определения, что и макросы Microsoft Windows с тем же именем. Макросы Windows определены в Winnt.h
.
Макрос | Возвращаемое значение |
---|---|
#CONTAINING_RECORD(адрес, тип, поле) | Возвращает базовый адрес экземпляра структуры, учитывая тип структуры и адрес поля в структуре. |
#FIELD_OFFSET(Тип, поле) | Возвращает смещение байтов именованного поля в известном типе структуры. |
#RTL_CONTAINS_FIELD(Структура, размер, поле) | Указывает, включает ли заданный размер байтов требуемое поле. |
#RTL_FIELD_SIZE(Тип, поле) | Возвращает размер поля в структуре известного типа, не требуя типа поля. |
#RTL_NUMBER_OF(Массив) | Возвращает количество элементов в массиве статического размера. |
#RTL_SIZEOF_THROUGH_FIELD(Тип, поле) | Возвращает размер структуры известного типа, вплоть до указанного поля. |
В этом примере показано использование #FIELD_OFFSET
макроса для вычисления смещения байтов в поле в структуре.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
См. также
Выражения MASM и выражения C++