많은 걸 생각하게 되네요
내공이 부럽습니다 ^^;;;;;
감사합니다
빌더(TWx) 님이 쓰신 글 :
: 코딩 님이 쓰신 글 :
: : procedure f(var v);
: : begin
: :
: : end;
: :
: : procedure TForm1.Button1Click(Sender: TObject);
: : var
: : str: string;
: : i: integer;
: : begin
: : i := 777;
: : str := 'hello';
: : f(i);
: : f(str);
: : end;
: :
: :
: : v가 타입 없는 var로 되어 있는데요
: :
: : 프로시져 f 에서 v 의 타입이 string 인지 integer 인지 알수 있는 방법이 있을까요?
: :
: : 델마당에 올라온 질문인데요
: : 제 생각으론 아무리 생각해봐도 불가능 할것 같긴한데요
: : 혹시나 해서 여쭈어 봅니다.
: :
:
:
:
: 답변:
:
:
: 도움말만 봐도 알수 있는 단순한 컴포넌트 사용법 관련된 글이면 한번 읽고 지나쳤을 텐데...
: 기술적인 부분이라 답변 글 남깁니다.
:
:
: CPU의 고유한 ID 값을 알아내기 위해 메인보드의 롬바이오스 SMB Bios 펌웨어 테이블 파싱이 필요하고
: 펌웨어 테이블의 자료구조 상... 테이블 파싱을 위해 T** two pointer 타입의 포인터 연산이 자주 사용되는데
:
: C++에선 T1 ** 타입을 T2 *& 으로 포인터에 대한 레퍼런스 타입으로 치환해서 포인터 연산을 간략하게 할 수 있으나
:
: T1 ** p;
: T2 v = *((T2 *&)p)++;
:
: T** two 포인터 연산을 파스칼로 작성하면 코드가 지져분해지므로 속편하게 예제는 어셈블리 코드로 작성 합니다.
:
:
: Object Inspector 를 통해 다양한 타입을 참조할 수 있는데... Boolean 타입을 예로 들어 봅시다.
: 부울형의 경우 True, False 값을 Object Inspector 에서 표시해 주죠.
: 이와 같은 메카니즘이 가능한 것은 델파이 컴파일러에 의해서 Rtti 정보가 바이너리로 Emit 되기 때문인데요.
: (Object Inspector를 통해서 보여지는 타입 정보들은 컴파일러에 의해 바이너리로 Emit 된 Rtti 정보 중에서
: published 된 극히 일부분에 불과함)
:
: Boolean 타입의 정보를 런타임 중에 바이너리에서 직접 찾아서 표시하는 예를 들어 봅시다.
:
:
: function GetBooleanType(): string;
: type PS = PShortString;
: var tn, v1, v2: DWORD;
: begin
: asm
: mov esi, $1000
: push 0
: call GetModuleHandle
: add esi, eax
: mov esi, [esi]
: lea esi, [esi + 1]
: mov tn, esi
: mov al, [esi]
: movzx eax, al
: lea esi, [eax + esi + 14]
: mov v1, esi
: mov al, [esi]
: movzx eax, al
: lea esi, [eax + esi + 1]
: mov v2, esi
: end;
: Result := 'typeName: ' + PS(tn)^ + ' ,v1: ' + PS(v1)^ + ' ,v2: ' + PS(v2)^;
: end;
:
: procedure TForm1.Button1Click(Sender: TObject);
: begin
: Memo1.Lines.Add( GetBooleanType() );
: end;
:
:
:
:
:
:
: 위의 경우는 Boolean 타입 하나만 예로 든 거고...
:
: class, record, virtual method, propery, message handler, event handler, class method, interface method 등등
: 델파이로 컴파일 되어있는 바이너리의 모든 타입 정보들을 리버스 엔지니어링으로 바이너리로 부터 직접 알아 낼수 있지요.
:
:
: 그리고...
:
:
: procedure f(var v);
: begin
:
: end;
:
: procedure TForm1.Button1Click(Sender: TObject);
: var
: str: string;
: i: integer;
: begin
: i := 777;
: str := 'hello';
: f(i);
: f(str);
: end
:
:
: procedure f(var v); 에서 v 의 타입을 알아내는 건...
:
: 컴파일러에 의해서 타입 정보가 넘어오지 않아서 일견 보기에는 불가능해 보일 수도 있으나
: 넘어온 파라미터 v 가 string 과 integer 둘 중에 하나라는 조건이 주어지고
: 델파이 컴파일러 내부구조를 알고 있으면 이 또한 가능 합니다.
:
:
:
: procedure Foo(var V);
: var mi: array[0..27] of Byte;
: begin
: asm
: mov esi, V
: mov esi, [esi]
: lea esi, [esi - 12];
: lea edi, mi
: push 28
: push edi
: push esi
: call VirtualQuery
: mov [edi + 16], eax
: and eax, eax
: je @skip
: add esi, 12
: and dword ptr [edi + 20], $24
: mov dword ptr [edi + 20], esi
: je @next
: cmp dword ptr[esi - 12], $204b0
: jnz @next
: mov byte ptr[edi + 16], 2
: jmp @skip
: @next:
: mov byte ptr[edi + 16], 1
: @skip:
: end;
:
: if mi[16] = 1 then
: Form1.Memo1.Lines.Add(Format('type: integer, value: %d', [PInteger(@mi[20])^]))
: else if mi[16] = 2 then
: Form1.Memo1.Lines.Add(Format('type: string, value: %s', [PChar(PDword(@mi[20])^)]))
: else
: Form1.Memo1.Lines.Add('Fail: VirtualQuery()')
: end;
:
: procedure TForm1.Button1Click(Sender: TObject);
: var
: s: string;
: i: integer;
: begin
: i := 777;
: s := 'hello';
:
: Foo(i);
: Foo(s);
: end;
:
:
:
:
:
:
:
: 모든 코드는 Rad studio 10.3.1 기준으로 작성.
:
:
: