C++ 숫자 및 연산자
이 문서에서는 Windows 디버깅 도구에서 C++ 식 구문을 사용하는 것에 대해 설명합니다.
디버거는 C++ 식과 MASM(Microsoft Macro Assembler) 식의 두 가지 숫자 식을 허용합니다. 이러한 각 식은 입력 및 출력에 대한 고유한 구문 규칙을 따릅니다.
각 구문 형식이 사용되는 시기에 대한 자세한 내용은 식 평가 및 식 평가 명령을 참조하세요.
C++ 식 파서는 모든 형태의 C++ 식 구문을 지원합니다. 구문에는 포인터, 부동 소수점 숫자 및 배열, 모든 C++ 단항 및 이진 연산자를 비롯한 모든 데이터 형식이 포함됩니다.
디버거의 Watch 및 Locals 창은 항상 C++ 식 계산기를 사용합니다.
다음 예제 에서 ?? evaluate 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
기본 식 계산기가 변경된 후에는 ? evaluate 식 명령을 사용하여 C++ 식을 표시할 수 있습니다. 다음 예제에서는 명령 포인터 레지스터의 값을 표시합니다.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
레지스터 참조에 @eip
대한 자세한 내용은 레지스터 구문을 참조 하세요.
이 예제에서는 0xD 16진수 값이 eip 레지스터에 추가됩니다.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
C++ 식에 등록 및 의사 레지스터
C++ 식 내에서 레지스터 및 의사 레지스터를 사용할 수 있습니다. @ 기호는 레지스터 또는 의사 등록 전에 추가해야 합니다.
식 계산기는 적절한 캐스트를 자동으로 수행합니다. 실제 레지스터 및 정수-값 의사 레지스터가 캐스팅 ULONG64
됩니다. 모든 주소가 캐스팅되고, $thread
캐스팅되고, $proc
캐스팅ETHREAD*
EPROCESS*
되고, $teb
캐스팅TEB*
되고, 캐스팅되고$peb
, 캐스팅됩니다PEB*
.PUCHAR
다음은 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++ 식의 숫자는 다른 방식으로 지정하지 않는 한 소수 숫자로 해석됩니다. 16진수를 지정하려면 숫자 앞에 0x를 추가합니다. 8진수를 지정하려면 숫자 앞에 0을 추가합니다.
기본 디버거 radix는 C++ 식을 입력하는 방법에 영향을 주지 않습니다. C++ 식 내에 MASM 식을 중첩하는 경우를 제외하고는 이진 번호를 직접 입력할 수 없습니다.
xxxx'xxxx 형식으로 16진수 64비트 값을 입력할 수 있습니다. 무덤 악센트(')를 생략할 수도 있습니다. 두 형식 모두 동일한 값을 생성합니다.
정수 U
값과 I64
접미사를 사용할 L
수 있습니다. 생성된 숫자의 실제 크기는 접미사와 입력한 수에 따라 달라집니다. 이 해석에 대한 자세한 내용은 C++ 언어 참조를 참조하세요.
C++ 식 계산기의 출력은 C++ 식 규칙이 지정하는 데이터 형식을 유지합니다. 그러나 이 식을 명령에 대한 인수로 사용하는 경우 캐스트는 항상 만들어집니다. 예를 들어 명령 인수에서 주소로 사용되는 경우 정수 값을 포인터로 캐스팅할 필요가 없습니다. 식의 값을 정수 또는 포인터로 올바르게 캐스팅할 수 없는 경우 구문 오류가 발생합니다.
일부 출력에는 0n
(10진수) 접두사를 사용할 수 있지만 C++ 식 입력에는 사용할 수 없습니다.
C++ 식의 문자 및 문자열
문자를 작은따옴표(')로 묶어 입력할 수 있습니다. 표준 C++ 이스케이프 문자가 허용됩니다.
큰따옴표(")로 묶어 문자열 리터럴을 입력할 수 있습니다. \"를 이러한 문자열 내에서 이스케이프 시퀀스로 사용할 수 있습니다. 그러나 문자열은 식 계산자에 아무런 의미가 없습니다.
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
다음 예제에서는 참조된 구조체의 멤버에 대한 포인터 사용을 보여 주는 프로세스 ID를 TEB 구조에 표시합니다.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
C++ 식의 연산자
괄호를 사용하여 우선 순위 규칙을 재정의할 수 있습니다.
C++ 식의 일부를 괄호로 묶고 식 앞에 두 개의 기호(@@)를 추가하면 식이 MASM 식 규칙에 따라 해석됩니다. 두 기호와 여는 괄호 사이에 공백을 추가할 수 없습니다. 이 식의 최종 값은 C++ 식 계산기로 ULONG64 값으로 전달됩니다. 식 계산기를 사용하거나 @@masm( ... )
.를 사용하여 @@c++( ... )
지정할 수도 있습니다.
데이터 형식은 C++ 언어로 평소와 같이 표시됩니다. 배열([ ]), 포인터 멤버(->), UDT 멤버(.) 및 클래스의 멤버(::)를 나타내는 기호가 모두 인식됩니다. 할당 및 부작용 연산자를 포함하여 모든 산술 연산자가 지원됩니다. 그러나 , delete
및 throw
연산자를 new
사용할 수 없으며 실제로 함수를 호출할 수는 없습니다.
포인터 산술 연산이 지원되고 오프셋의 크기가 올바르게 조정됩니다. 함수 포인터에 오프셋을 추가할 수 없습니다. 함수 포인터에 오프셋을 추가해야 하는 경우 먼저 오프셋을 문자 포인터로 캐스팅합니다.
C++에서와 같이 잘못된 데이터 형식의 연산자를 사용하는 경우 구문 오류가 발생합니다. 디버거의 C++ 식 파서는 대부분의 C++ 컴파일러보다 약간 더 완화된 규칙을 사용하지만 모든 주요 규칙이 적용됩니다. 예를 들어 정수가 아닌 값은 이동할 수 없습니다.
다음 연산자를 사용할 수 있습니다. 각 셀의 연산자가 하위 셀의 연산자보다 우선합니다. 동일한 셀의 연산자는 동일한 우선 순위이며 왼쪽에서 오른쪽으로 구문 분석됩니다.
C++와 마찬가지로 식 계산은 값이 알려지면 종료됩니다. 이 끝은 다음과 같은 ?? myPtr && *myPtr
식을 효과적으로 사용할 수 있게 해줍니다.
참조 및 형식 캐스팅
연산자 | 의미 |
---|---|
식 // 주석 | 모든 후속 텍스트 무시 |
클래스 :: 멤버 | 클래스의 멤버 |
클래스 ::~Member | 클래스의 멤버(소멸자) |
:: 이름 | 전역 |
구조 필드 | 구조체의 필드 |
포인터 ->Field | 참조된 구조의 필드 |
이름 [정수] | 배열 첨자 |
LValue ++ | 증분(평가 후) |
LValue -- | 감소(평가 후) |
<dynamic_cast type>(Value) | Typecast(항상 수행됨) |
<static_cast type>(Value) | Typecast(항상 수행됨) |
<reinterpret_cast type>(Value) | Typecast(항상 수행됨) |
<const_cast type>(Value) | Typecast(항상 수행됨) |
값 작업
연산자 | 의미 |
---|---|
(type) 값 | Typecast(항상 수행됨) |
sizeof 값 | 식 크기 |
sizeof( type ) | 데이터 형식의 크기 |
++ LValue | 증분(평가 전) |
-- LValue | 감소(평가 전) |
~ 값 | 비트 보수 |
! 값 | Not(Boolean) |
값 | 단항 빼기 |
+ 값 | 단항 더하기 |
& LValue | 데이터 형식의 주소 |
값 | Dereference |
구조 포인터 | 구조체의 멤버에 대한 포인터 |
포인터 -> * 포인터 | 참조된 구조체의 멤버에 대한 포인터 |
산술
연산자 | 의미 |
---|---|
값 값 | 곱하기 |
값 / 값 | 나누기 |
값 % 값 | 모듈러스 |
값 + 값 | 더하기 |
값 - 값 | 빼기 |
값<<값 | 왼쪽으로 비트 이동 |
값>>값 | 오른쪽으로 비트 이동 |
값<값 | 보다 작음(비교) |
값<= 값 | 작거나 같음(비교) |
값>값 | 보다 큼(비교) |
값>= 값 | 크거나 같음(비교) |
값 == 값 | 같음(비교) |
값 != 값 | 같지 않음(비교) |
값 및 값 | 비트 AND |
값 ^ 값 | 비트 XOR(전용 OR) |
값 | 값 | 비트 OR |
값 및 값 | 논리적 AND |
값 || 값 | 논리적 OR |
다음 예제에서는 의사 레지스터가 표시된 대로 설정된다고 가정합니다.
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 &= 값 | AND 및 할당 |
LValue |= 값 | OR 및 할당 |
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