Share via


C++ 숫자 및 연산자

이 문서에서는 Windows 디버깅 도구에서 C++ 식 구문을 사용하는 것에 대해 설명합니다.

디버거는 C++ 식과 MASM(Microsoft Macro Assembler) 식의 두 가지 숫자 식을 허용합니다. 이러한 각 식은 입력 및 출력에 대한 고유한 구문 규칙을 따릅니다.

각 구문 형식이 사용되는 시기에 대한 자세한 내용은 식 평가식 평가 명령을 참조하세요.

C++ 식 파서는 모든 형태의 C++ 식 구문을 지원합니다. 구문에는 포인터, 부동 소수점 숫자 및 배열, 모든 C++ 단항 및 이진 연산자를 포함한 모든 데이터 형식이 포함됩니다.

디버거의 조사 식 및 로컬 창은 항상 C++ 식 계산기를 사용합니다.

다음 예제에서 ?? evaluate C++ 식 명령은 명령 포인터 레지스터의 값을 표시합니다.

0:000> ?? @eip
unsigned int 0x771e1a02

C++ sizeof 함수를 사용하여 구조체의 크기를 확인할 수 있습니다.

0:000> ?? (sizeof(_TEB))
unsigned int 0x1000

식 계산기를 C++로 설정

.expr choose 식 계산기를 사용하여 기본 식 계산기를 확인하고 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캐스팅됩니다. 모든 주소는 로 PUCHAR$thread 캐스팅되고, 은 로 $proc 캐스팅ETHREAD*되고, 은 로 $teb 캐스팅EPROCESS*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++ 식의 숫자는 다른 방식으로 지정하지 않는 한 소수 숫자로 해석됩니다. 16진수 정수를 지정하려면 숫자 앞에 0x를 추가합니다. 8진수를 지정하려면 숫자 앞에 0을 추가합니다.

기본 디버거 radix는 C++ 식을 입력하는 방법에 영향을 주지 않습니다. C++ 식 내에 MASM 식을 중첩하는 경우를 제외하고는 이진 번호를 직접 입력할 수 없습니다.

xx'xxxx 형식으로 16진수 64비트 값을 입력할 수 있습니다. 무덤 악센트(')를 생략할 수도 있습니다. 두 형식 모두 동일한 값을 생성합니다.

정수 값과 L함께 , UI64 접미사를 사용할 수 있습니다. 생성된 숫자의 실제 크기는 접미사와 입력한 수에 따라 달라집니다. 이 해석에 대한 자세한 내용은 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

다음 예제에서는 참조된 구조체의 멤버에 대한 포인터의 사용을 보여 주는 TEB 구조체의 프로세스 ID를 표시합니다.

0:000> ??  @$teb->ClientId.UniqueProcess
void * 0x0000059c

C++ 식의 연산자

괄호를 사용하여 우선 순위 규칙을 재정의할 수 있습니다.

C++ 식의 일부를 괄호로 묶고 식 앞에 두 개의 at sign(@@)을 추가하면 식이 MASM 식 규칙에 따라 해석됩니다. 두 기호와 여는 괄호 사이에 공백을 추가할 수 없습니다. 이 식의 최종 값은 C++ 식 계산기로 ULONG64 값으로 전달됩니다. 또는 @@masm( ... )를 사용하여 @@c++( ... ) 식 계산기를 지정할 수도 있습니다.

데이터 형식은 C++ 언어로 평소와 같이 표시됩니다. 배열([ ]), 포인터 멤버(->), UDT 멤버(.) 및 클래스의 멤버(::)를 나타내는 기호가 모두 인식됩니다. 할당 및 부작용 연산자를 포함하여 모든 산술 연산자가 지원됩니다. 그러나 , deletethrow 연산자는 new사용할 수 없으며 실제로 함수를 호출할 수 없습니다.

포인터 산술 연산이 지원되고 오프셋이 올바르게 조정됩니다. 함수 포인터에 오프셋을 추가할 수 없습니다. 함수 포인터에 오프셋을 추가해야 하는 경우 먼저 오프셋을 문자 포인터로 캐스팅합니다.

C++에서와 같이 잘못된 데이터 형식의 연산자를 사용하는 경우 구문 오류가 발생합니다. 디버거의 C++ 식 파서는 대부분의 C++ 컴파일러보다 약간 더 완화된 규칙을 사용하지만 모든 주요 규칙이 적용됩니다. 예를 들어 정수가 아닌 값은 이동할 수 없습니다.

다음 연산자를 사용할 수 있습니다. 각 셀의 연산자가 하위 셀의 연산자보다 우선합니다. 동일한 셀의 연산자는 동일한 우선 순위이며 왼쪽에서 오른쪽으로 구문 분석됩니다.

C++와 마찬가지로 식 계산은 값이 알려지면 종료됩니다. 이 끝은 와 같은 ?? myPtr && *myPtr식을 효과적으로 사용할 수 있게 해줍니다.

참조 및 형식 캐스팅

연산자 의미
// 코멘트 모든 후속 텍스트 무시
클래스 :: 멤버 클래스의 멤버
클래스 ::~Member 클래스의 멤버(소멸자)
:: 이름 전역
구조체 . 필드 구조체의 필드
포인터 ->필드 참조된 구조체의 필드
이름 [정수] 배열 첨자
Lvalue ++ 증분(평가 후)
Lvalue -- 감소(평가 후)
Dynamic_cast<형식>() Typecast(항상 수행됨)
Static_cast<형식>() Typecast(항상 수행됨)
< reinterpret_cast형식>() Typecast(항상 수행됨)
< const_cast형식>() Typecast(항상 수행됨)

값 작업

연산자 의미
(type) Typecast(항상 수행됨)
sizeof 식 크기
sizeof( type ) 데이터 형식의 크기
++ Lvalue 증분(평가 전)
-- Lvalue 감소(평가 전)
~ Value 비트 보수
! 아님(부울)
단항 빼기
+ Value 단항 더하기
& 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(Address, Type, Field) 구조체의 형식과 구조체 내 필드의 주소를 고려하여 구조체의 instance 기본 주소를 반환합니다.
#FIELD_OFFSET(Type, Field) 알려진 구조체 형식의 명명된 필드의 바이트 오프셋을 반환합니다.
#RTL_CONTAINS_FIELD(구조체, 크기, 필드) 지정된 바이트 크기에 원하는 필드가 포함되는지 여부를 나타냅니다.
#RTL_FIELD_SIZE(Type, Field) 필드의 형식을 요구하지 않고 알려진 형식의 구조로 필드의 크기를 반환합니다.
#RTL_NUMBER_OF(Array) 정적으로 크기가 지정된 배열의 요소 수를 반환합니다.
#RTL_SIZEOF_THROUGH_FIELD(Type, Field) 지정된 필드를 포함하여 알려진 형식의 구조체 크기를 반환합니다.

이 예제에서는 매크로를 #FIELD_OFFSET 사용하여 구조체의 필드에 대한 바이트 오프셋을 계산하는 방법을 보여줍니다.

0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2

추가 정보

MASM 식과 C++ 식

?? C++ 식 평가

? evaluate 식

.expr 식 계산기 선택

서명 확장

혼합 식 예제