많은 걸 생각하게 되네요
내공이 부럽습니다 ^^;;;;;
감사합니다
빌더(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 기준으로 작성.
: 
: 
: