Подскажите пожалуйста ответ. Задача такая - написать в Delphi (семерка) процедуру выводящую номер строки исходника с которой она была вызвана (ну, что-то подобное Assert). Единственное до чего удалось докопаться - Assert получает необходимую информацию при компиляции, но механизм под вопросом. Забавно - самой процедыры Assert в модуле System нет.
yunus самой процедыры Assert в модуле System нет Ты невнимателен. Source\Rtl\Sys\System.pas строки с 11477 по 11515 Код (Text): procedure _Assert(const Message, Filename: AnsiString; LineNumber: Integer); {$IFDEF PUREPASCAL} begin if Assigned(AssertErrorProc) then AssertErrorProc(Message, Filename, LineNumber, Pointer(-1)) else Error(reAssertionFailed); // loses return address end; {$ELSE} asm PUSH EBX {$IFDEF PIC} PUSH EAX PUSH ECX CALL GetGOT MOV EBX, EAX MOV EAX, [EBX].AssertErrorProc CMP [EAX], 0 POP ECX POP EAX {$ELSE} CMP AssertErrorProc,0 {$ENDIF} JNZ @@1 MOV AL,reAssertionFailed CALL Error JMP @@exit @@1: PUSH [ESP+4].Pointer {$IFDEF PIC} MOV EBX, [EBX].AssertErrorProc CALL [EBX] {$ELSE} CALL AssertErrorProc {$ENDIF} @@exit: POP EBX end; {$ENDIF} механизм под вопросом Поставь точку останова перед вызовом Assert и посмотри в окне cpu как он оформлен. Увидишь что-то вроде Код (Text): mov ecx,константа_с_номером_строки mov edx,адрес_строки_с_именем_модуля mov eax,адрес_строки_с_сообщением call @Assert до этих инструкция расположена проверка условия вызова. Т.е. номер строки фигурирует в программе как константа, определенная компилятором. Afaik в delphi нет макросов аналогичных Си’шным __FILE__ и __LINE__ и получить их красиво не получится, я не знаю и не красивого способа.
Да, спасибо, до этого я докопался (при этом мне таки кажется assert и _assert две разные беды). По моему соображению компилятор встретив в теле проги обращение к Assert формирует следующий код - заполняет три регистра и вызывает _Assert из System. Переиначу вопрос таким образом - как этот компилятор узнает, что перед ним именно Assert (не по имени же !) и нельзя ли как-нибудь прикинуться этим Assert-ом и заставить Delphi сгенерить для моей процедурки именно такой код ?
yunus мне таки кажется assert и _assert две разные Трассируй вызов call @Assert и поймешь, что @Assert == _Assert == Assert. как-нибудь прикинуться этим Assert-ом Можно в качестве AssertErrorProc задать адрес своей процедуры. заставить Delphi сгенерить для моей процедурки именно такой код Какой код?
трасировал и получил вот что - Код (Text): DelphiUnit.PAS.232 Assert(not condition, message); test bl,bl jz TAssert.IsFalse + $36 mov ecx, $000000e8 mov edx, $01174db8 call @Assert xor eax, eax pop edx - то есть Assert всетаки не просто вызов _Assert а что-то наподобии служебного слова. Встретив этот "Assert" в тексте программы компилятор творит совершенно нестандартный код вызова - при этом один из аргументов (condition) вообще не передается в процедуру - а проверяется до вызова (test bl, bl), зато передаются два скрытых параметра (номер строки и имя модуля) - известные к сожалению только компилятору. Когда я "мечтал" прикинуться Assert-ом, я имел ввиду - состряпать такую процедуру которая вызвала бы у компилятора такую же реакцию, и которой он бы сформировал именно такой код вызова.