Debugging Tools for Windows |
C++ 表达式解析器支持所有 C++ 表达式语法形式。包括所有数据类型(包括指针,浮点数,数组)以及 C++ 所有一元和二元运算符。
除非另有说明,C++ 表达式中的数值被当作十进制来解析。添加 0x 前缀指定十六进制整数。添加 0(零)指定八进制整数。
调试器使用的缺省基数不影响 C++ 表达式的输入。不能直接输入二进制数值(除非在 C++ 表达式中嵌套 MASM 表达式)。
能够以 xxxxxxxx`xxxxxxxx 格式输入 64 位十六进制数值(可以忽略重音符号(`))。两种格式值相同。
整型值后可以使用 L、U 和 I64 后缀。合成数的实际大小依据使用的后缀和输入的数值;详细请看 C++ 语言参考。
C++ 表达式求值后的输出结果保留 C++ 表达式规则指定的数据类型。然而,如果表达式被用作某个命令的参数,总是会产生强制类型转换。例如,在命令参数中作为地址时你不需要把整型值强制转换为指针。如果表达式的值不能被合法地强制转换为整型或者指针,则会导致语法错误。
某些输出中会用到 0n(十进制)前缀,虽然在输入 C++ 表达式时不允许使用该前缀。
输入字符时用单引号(')括住。可以使用标准的 C++ 转义字符。
输入字符串时用双引号(")括住。可以在字符串中使用转义字符序列 \" 。然而,字符串对于表达式求值器无意义。
在 C++ 表达式中,每个符号都根据它的类型来解析。根据引用符号的不同,可以被解析为整数、数据结构、函数指针或者其它的数据类型。在 C++ 表达式中使用一个没有 C++ 数据类型与之对应的符号(例如一个没有修饰的模块名)会导致语法错误。
如果会混淆,可以在符号前添加模块名和感叹号(!)前缀,或者单独一个感叹号前缀。关于符号识别,详细请看符号语法和符号匹配。
只有以模块名和感叹号为前缀的符号名中才能使用重音符号(`)或者撇号(')。
当模板名用 < 和 > 分隔符时,分隔符之间可以有空格。
总是可以用圆括号来掩盖优先级规则。
如果 C++ 表达式的某一部分被圆括号括住并且在表达式前添加两个at符号(@@),该部分将根据 MASM 表达式规则来解析。在两个 @ 记号之间以及和左圆括号之间不能有空格。该表达式的最终值将以 ULONG64 类型传递给 C++ 表达式求解器。也可以通过使用 @@c++( ... ) 或者 @@masm( ... ) 指定表达式求解器。
数据类型按C++语言的常规方法来指定。可以识别表示数组([ ]),指针成员(->),UDT(译注:用户定义类型,User defined types)成员(.),以及所有的类成员(::)。支持所有算术运算符,包括赋值运算符和带副作用的运算符。但是,不允许使用 new、delete 和 throw 运算符,当然,也不能调用函数。
支持指针运算,也可以正确计算偏移。注意不能给函数指针加上某个偏移值 (如果需要这样做,首先把它强制转换为指向字符的指针)。
和在 C++ 中一样,使用带非法数据类型的运算符将导致语法错误。调试器中的 C++ 表达式解析器比大多数 C++ 编译器使用的规则要稍微宽松一些,但所有的主要规则都支持。例如,非整型数移位操作是被禁止的。
下表列出了所有可用的运算符。各个单元格中的运算符优先级从上往下依次降低。同一格中的各个运算符优先级相同,以从左往右的方式解析。和 C++ 一样,如果表达式的值已经可以确定,则终止继续求值过程;这个规则允许有效地使用如 ?? myPtr && *myPtr 样子的表达式。
操作符 | 含义 |
---|---|
Expression // Comment | 注释,忽略后面的所有文本 |
Class :: Member Class ::~Member :: Name |
类成员 类成员(析构函数) 全局的 |
Structure . Field Pointer -> Field Name [integer] LValue ++ LValue -- dynamic_cast <type>(Value) static_cast <type>(Value) reinterpret_cast <type>(Value) const_cast <type>(Value) |
结构成员 被引用结构的成员 数组下标 加一(计算后) 减一(计算后) 类型强制转换(总会执行) 类型强制转换(总会执行) 类型强制转换(总会执行) 类型强制转换(总会执行) |
(type) Value sizeof value sizeof( type ) ++ LValue -- LValue ~ Value ! Value - Value + Value & LValue * Value |
类型强制转换(总会执行) 表达式大小 数据类型大小 加一(计算前) 减一(计算前) 按位反 逻辑非 一元运算符,负数 一元运算符,正数 数据类型的地址 解引用,取值 |
Structure . * Pointer Pointer -> * Pointer |
指向结构成员的指针 指向被引用结构的成员的指针 |
Value * Value Value / Value Value % Value |
乘法 除法 求余 |
Value + Value Value - Value |
加法 减法 |
Value << Value Value >> Value |
左移位 右移位 |
Value < Value Value <= Value Value > Value Value >= Value |
小于(比较) 小于等于(比较) 大于(比较) 大于等于(比较) |
Value == Value Value != Value |
等于(比较) 不等于(比较) |
Value & Value | 按位与 |
Value ^ Value | 按位异或(不同于 OR) |
Value | Value | 按位或 |
Value && Value | 逻辑与 |
Value || Value | 逻辑或 |
LValue = Value LValue *= Value LValue /= Value LValue %= Value LValue += Value LValue -= Value LValue <<= Value LValue >>= Value LValue &= Value LValue |= Value LValue ^= Value |
赋值 乘之后赋值 除之后赋值 求余之后赋值 加之后赋值 减之后赋值 左移位之后赋值 右移位之后赋值 与之后赋值 或之后赋值 异或之后赋值 |
Value ? Value : Value | 三元条件运算符 |
Value , Value | 逗号运算符。计算所有值,保留最右边的值 |
C++ 表达式中可以使用寄存器和伪寄存器。它们必须带一个 at符号(@) 前缀。
表达式求解器会自动执行正确的强制类型转换。实际的寄存器和整型值伪寄存器被强制转换为 ULONG64。所有地址被强制转换为 PUCHAR,$thread 被强制转换为 ETHREAD*,$proc 被强制转换为 EPROCESS*,$teb 被强制转换为 TEB*,$peb 被强制转换为 PEB*。
不能使用赋值运算符或者带副作用的运算符修改寄存器或者伪寄存器。必须使用 r (Registers)命令修改它们的值。
在C++表达式中可以使用宏。必须在宏前面加上数字符号(#)。
可以使用下表中的宏。这些宏的作用和Microsoft Windows中定义的同名宏有相同的定义。(Windows的宏在Winnt.h中定义。)
宏 | 返回值 |
---|---|
#CONTAINING_RECORD(Address, Type, Field) | 给定该结构的类型和它包含的一个字段的地址,返回该结构实例的基地址。 |
#FIELD_OFFSET(Type, Field) | 返回一个已知的结构类型中某个命名字段的字节偏移。 |
#RTL_CONTAINS_FIELD (Struct, Size, Field) | 指出是否给定的字节大小包含了需要的字段。 |
#RTL_FIELD_SIZE(Type, Field) | 返回已知类型的结构中某个字段的大小,不需要给出该字段的类型。 |
#RTL_NUMBER_OF(Array) | 返回一个静态分配的数组的元素个数。 |
#RTL_SIZEOF_THROUGH_FIELD(Type, Field) | 返回已知类型的结构中,从基地址到包含指定字段的位置的大小。 |