English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5 Programlarında Hata Ayıklama

MQL5 Programlarında Hata Ayıklama

MetaTrader 5Örnekler | 13 Ocak 2022, 09:42
176 0
Mykola Demko
Mykola Demko

Giriş

Bu makale öncelikle dili öğrenmiş, ancak henüz program geliştirme konusunda tam olarak uzmanlaşmamış programcılara yöneliktir. Bir programda hata ayıklarken her geliştiricinin uğraştığı temel sorunları vurgular. Peki, hata ayıklama nedir?

Hata ayıklama, program yürütme hatalarını algılamak ve gidermek için program geliştirmedeki bir aşamadır. Hata ayıklama işlemi sırasında geliştirici, olası sorunları algılamaya çalışarak bir uygulamayı analiz eder. Analiz için veriler, değişkenler ve program yürütme (hangi fonksiyonların ne zaman çağrıldığı) gözlemlenerek alınır.

İki tamamlayıcı hata ayıklama teknolojisi vardır:

  • hata ayıklayıcı: geliştirilmiş programın adım adım yürütmesini gösteren yardımcı yazılım.
  • Değişkenlerin durumlarını ve fonksiyonlarının çağrılarını bir ekranda, günlükte veya bir dosyada etkileşimli olarak görüntüleme.

Değişkenler, yapılar vb. dahil olmak üzere MQL5'i bildiğinizi varsayalım. Ancak henüz kendi başınıza programlar geliştirmediniz. Yapacağınız ilk şey bir derleme. Aslında, bu hata ayıklamanın ilk aşamasıdır.


1. Derleme

Derleme, bir kaynak kodunu yüksek seviyeli programlama dilinden düşük seviyeli bir dile çevirmektir.

MetaEditor derleyicisi, programları yerel bir koda değil, bir bayt koduna çevirir (ayrıntılar için bağlantıyı izleyin). Bu, şifreli programlar geliştirilmesine olanak sağlar. Ayrıca, bir bayt kodu hem 32 hem de 64 bit işletim sistemlerinde başlatılabilir.

Ancak hata ayıklamanın ilk aşaması olan derlemeye geri dönelim. F7'ye (veya Derle düğmesine) bastıktan sonra, MetaEditor 5, kodu yazarken yaptığınız tüm hataları rapor edecektir. "Araç Kutusu" penceresinin "Hatalar" sekmesi, algılanan hataların açıklamasını ve konumlarını içerir. Açıklama satırını imleç ile vurgulayın ve doğrudan hataya gitmek için Enter tuşuna basın.

Derleyici tarafından yalnızca iki tür hata görüntülenir:

  • Söz dizimi hataları (kırmızı ile gösterilir): Kaynak kod, bunlar ortadan kaldırılıncaya kadar derlenemez.
  • Uyarılar (sarı ile gösterilir): Kod derlenecektir, ancak bu hataları düzeltmek iyi olacaktır.

Söz dizimi hataları genellikle dikkatsizlikten kaynaklanır. Örneğin, "," ve ";" değişkenleri bildirirken kolayca karıştırılabilir:

int a; b; // incorrect declaration

Böyle bir bildirim olması durumunda derleyici bir hata döndürür. Doğru bildirim aşağıdaki gibi görünecektir:

int a, b; // correct declaration

Veya:

int a; int b; // correct declaration

Uyarılar da göz ardı edilmemelidir (birçok geliştirici uyarılar konusunda çok dikkatsizdir). MetaEditor 5, derleme sırasında uyarılar döndürürse, bir program oluşturulur, ancak bunun planladığınız gibi çalışacağının garantisi yoktur.

Uyarılar, MQL5 geliştiricilerinin, programcıların yaygın yazım hatalarını sistematize etmeye yönelik büyük çabalarını gizleyen buzdağının yalnızca görünen kısmıdır.

İki değişkeni karşılaştıracağınızı varsayalım:

if(a==b) { } // if a is equal to b, then ...

Ancak bir yazım hatası veya unutkanlık nedeniyle "==" yerine "=" kullandınız. Bu durumda, derleyici kodu şu şekilde yorumlar:

if(a=b) { } // assign b to a, if a is true, then ... (unlike MQL4, it is applicable in MQL5)

Gördüğümüz gibi, bu yazım hatası programın işleyişini önemli ölçüde değiştirebilir. Bu nedenle, derleyici bu satır için uyarı gösterecektir.

Özetleyelim: Derleme hata ayıklamanın ilk aşamasıdır. Derleyici uyarıları göz ardı edilmemelidir.

Şekil 1. Derleme sırasında hata ayıklama verisi

Şekil 1. Derleme sırasında hata ayıklama verisi.


2. Hata ayıklayıcı

İkinci hata ayıklama aşaması, Hata ayıklayıcı (F5 kısayol tuşu) kullanımıdır. Hata ayıklayıcı, programınızı adım adım yürüterek öykünme modunda başlatır. Hata Ayıklayıcı, MetaEditor 4'te bulunmadığından MetaEditor 5'in yeni bir özelliğidir. Bu nedenle, MQL4'ten MQL5'e geçiş yapan programcıların kullanım tecrübesi yoktur.

Hata ayıklayıcı arayüzünde üç ana ve üç yardımcı düğme bulunur:

  • Başlat [F5] - hata ayıklamayı başlat.
  • Duraklat [Kesme] - hata ayıklamayı duraklat.
  • Durdur [Shift+F5] - hata ayıklamayı durdur.
  • İçine Adımla [F11] - kullanıcı bu satırda çağrılan fonksiyon içine hareket ettirilir.
  • Üzerinden Adımla [F10] - hata ayıklayıcı bu dizede çağrılan fonksiyon gövdesini yok sayar ve sonraki satıra geçer.
  • Dışına Adımla [Shift+F11] - bir kullanıcı mevcut olarak bulunduğu fonksiyon gövdesinden çıkar.

Hata ayıklayıcının arayüzü budur. Ama bunu nasıl kullanmalıyız? Program hata ayıklaması, bir programcının özel DebugBreak() hata ayıklama fonksiyonu ayarladığı satırdan veya F9 düğmesine basılarak veya araç çubuğundaki özel bir düğmeye tıklayarak ayarlanabilen bir kesme noktasından başlayabilir:

Şekil 2. Kesme noktalarını ayarlama

Şekil 2. Kesme noktalarını ayarlama.

Kesme noktaları olmadan, hata ayıklayıcı sadece programı yürütecektir ve hata ayıklamanın başarılı olduğunu bildirecektir, ancak siz hiçbir şey görmeyeceksiniz. DebugBreak kullanarak, ilgilenmediğiniz bazı kodları atlayabilir ve sorunlu olduğunu düşündüğünüz satırdan programı adım adım kontrol etmeye başlayabilirsiniz.

Yani, hata ayıklayıcıyı başlattık, DebugBreak'i doğru yere koyduk ve şimdi programın yürütülmesini inceliyoruz. Sırada ne var? Bu bize programda neler olduğunu anlamamızda nasıl yardımcı olabilir?

İlk olarak, hata ayıklayıcı penceresinin sol kısmına bakın. Şu anda bulunduğunuz satırın fonksiyon adını ve sayısını görüntüler. İkinci olarak, pencerenin sağ tarafına bakın. Burası boştur, ancak İfade alanına herhangi bir değişkenin adını girebilirsiniz. Mevcut değerini görmek için değişkenin adını Değer alanına girin.

Değişken aynı zamanda [Shift+F9] kısayol tuşu kullanılarak veya aşağıda gösterilen içerik menüsünden seçilebilir ve eklenebilir:

Şekil 3. Hata ayıklama sırasında değişken izleme ekleme

Şekil 3. Hata ayıklama sırasında değişken izleme ekleme.

Böylece o anda bulunduğunuz bir kod satırını izleyebilir ve önemli değişkenlerin değerlerini görüntüleyebilirsiniz. Tüm bunları analiz ederek, nihai olarak programın doğru çalışıp çalışmadığını anlayabileceksiniz.

Henüz bildirildiği fonksiyona ulaşmamışken ilgilendiğiniz değişkenin yerel olarak bildirilmesine dair endişelenmenize gerek yok. Değişkenin kapsamı dışındayken, "Bilinmeyen tanımlayıcı" değerine sahip olacaktır. Bu, değişkenin bildirilmediği anlamına gelir. Bu, hata ayıklayıcının hata vermesine neden olmaz. Değişkenin kapsamına ulaştıktan sonra bunun değerini ve türünü göreceksiniz.

Şekil 4. Hata ayıklama süreci - değişken değerlerine bakma

Şekil 4. Hata ayıklama süreci. Değişken değerlerine bakma.

Bunlar ana hata ayıklayıcı özellikleridir. Test bölümü, hata ayıklayıcıda nelerin yapılamayacağını gösterir.


3. Profil oluşturucu

Profil oluşturucu kodu hata ayıklayıcı için önemli bir eklentidir. Aslında bu, program hata ayıklamasının, bunun optimizasyonundan oluşan son aşamasıdır.

Profil oluşturucu, MetaEditor 5 menüsünden "Profil oluşturmayı başlat" düğmesine tıklanarak çağrılır. Hata ayıklayıcının sunduğu adım adım program analizi yerine, profil oluşturucu programı yürütür. Bir program bir gösterge veya bir Uzman Danışman ise, profil oluşturucu program kaldırılana kadar çalışacaktır. Kaldırma, grafikten bir gösterge veya bir Uzman Danışman kaldırılarak ve "Profil oluşturmayı durdur" tıklanarak gerçekleştirilebilir.

Profil oluşturma bize önemli istatistikler sağlar: her bir fonksiyonun kaç kez çağrıldığı, yürütülmesi için ne kadar zaman harcandığı. Belki yüzde cinsinden istatistikler biraz kafanızı karıştıracaktır. İstatistiklerin iç içe geçmiş fonksiyonları dikkate almadığını anlamak gerekir. Bu nedenle, tüm yüzde değerlerinin toplamı %100'ü büyük ölçüde aşacaktır.

Ancak, profil oluşturucu, kullanıcıların hız için hangi fonksiyonun optimize edilmesi gerektiğini ve nerede bellekten biraz tasarruf edebileceklerini görmelerine izin verecek şekilde programları optimize etmek için halen güçlü bir araç olarak kalmaktadır.

Şekil 5. Profil Oluşturucu işlem sonuçları

Şekil 5. Profil oluşturucu işlem sonuçları.


4. Etkileşim

Sanıyorum temel hata ayıklama araçları mesaj görüntüleme fonksiyonları: Yazdır ve Yorum. İlk olarak bunların kullanımları çok kolaydır. İkinci olarak, dilin önceki sürümünden MQL5'e geçiş yapan programcılar bunları zaten biliyorlar.

"Yazdır" fonksiyonu, aktarılan parametreyi günlük dosyasına ve Uzmanlar aracı sekmesine bir metin dizesi olarak gönderir. Gönderme zamanı ve fonksiyonu çağıran programın adı metnin solunda görüntülenir. Hata ayıklama sırasında, fonksiyon değişkenlerde hangi değerleriniçerildiğini tanımlamak için kullanılır.

Değişken değerlerine ek olarak, bazen bu fonksiyonların çağrılarının sırasını bilmek gerekir. "__FUNCTION__" ve "__FUNCSIG__" makroları bunun için kullanılabilir. İlk makro, çağrıldığı fonksiyonun adına sahip bir dize döndürürken ikincisi ek olarak çağrılan fonksiyonun parametrelerinin listesini görüntüler.

Aşağıda, makroların kullanımını görebilirsiniz:

//+------------------------------------------------------------------+
//| Example of displaying data for debugging                         |
//+------------------------------------------------------------------+
void myfunc(int a)
  {
   Print(__FUNCSIG__); // display data for debugging 
//--- here is some code of the function itself
  }

aşırı yüklü fonksiyonlar(aynı ada, ancak farklı parametrelere sahip) arasındaki farklı gösterdiğinden "__FUNCSIG__" makrosunu kullanmayı tercih ediyorum.

Genellikle bazı çağrıları atlamak veya hatta belirli bir fonksiyon çağrısına odaklanmak gerekir. Bu amaçla, Yazdır fonksiyonu bir koşul ile korunabilir. Örneğin, yazdır yalnızca 1013. yinelemeden sonra çağrılabilir:

//+------------------------------------------------------------------+
//| Example of data output for debugging                             |
//+------------------------------------------------------------------+
void myfunc(int a)
  {
//--- declare the static counter
   static int cnt=0;
//--- condition for the function call
   if(cnt==1013)
      Print(__FUNCSIG__," a=",a); // data output for debugging
//--- increment the counter
   cnt++;
//--- here is some code of the function itself
  }

Aynısı, bir grafiğin sol üst köşesinde yorumları görüntüleyen Yorum fonksiyonu için de yapılabilir. Hata ayıklama sırasında herhangi bir yere geçmeniz gerekmediği için bu büyük bir avantajdır. Ancak, fonksiyonu kullanırken her yeni yorum bir öncekini siler. Bu (bazen uygun olsa da) bir dezavantaj olarak görülebilir.

Bu dezavantajı ortadan kaldırmak için, değişkene yeni bir dizenin ek olarak yazılması yöntemi uygulanabilir. İlk olarak, dize türü değişkeni bildirilir (birçok durumda global olarak) ve boş değer ile başlatılır. Ardından, her yeni metin dizesi eklenen satır besleme karakteri ile başa yerleştirilirken değişkenin önceki değeri sona eklenir.

string com=""; // declare the global variable for storing debugging data
//+------------------------------------------------------------------+
//| Example of data output for debugging                             |
//+------------------------------------------------------------------+
void myfunc(int a)
  {
//--- declare the static counter
   static int cnt=0;
//--- storing debugging data in the global variable
   com=(__FUNCSIG__+" cnt="+(string)cnt+"\n")+com;
   Comment(com); // вывод информации для отладки
//--- increase the counter
   cnt++;
//--- here is some code of the function itself
  }

Burada, programın içeriğini ayrıntılı olarak görüntülemek için başka bir imkana geliyoruz: dosyaya yazdırma. Yazdır ve Yorumla fonksiyonları, büyük veri hacimleri veya yüksek hızlı yazdırma için her zaman uygun olmayabilir. İlki bazen değişiklikleri görüntülemek için yeterli zamana sahip olmayabilir (çağrılar ekranın önünden geçerek kafa karışıklığına neden olabilir), ikincisi de daha da yavaş çalışır. Ayrıca yorum tekrar okunamaz ve ayrıntılı olarak incelenemez.

Dosyaya yazdırma, çağrıların sırasını kontrol etmeniz veya büyük miktarda veriyi günlüğe kaydetmeniz gerektiğinde en uygun veri çıkışı yöntemidir. Ancak, yazdır seçeneğinin her yinelemede kullanılmadığı, bunun yerine dosyanın sonunda kullanıldığı ve dize değişkenine veri kaydetmenin yukarıda açıklanan ilkeye göre her yinelemede kullanıldığı unutulmamalıdır (tek fark yeni verilerin ek olarak değişkenin sonuna yazılmasıdır).

string com=""; // declare the global variable for storing debugging data
//+------------------------------------------------------------------+
//| Program shutdown                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- saving data to the file when closing the program
   WriteFile();
  }
//+------------------------------------------------------------------+
//| Example of data output for debugging                             |
//+------------------------------------------------------------------+
void myfunc(int a)
  {
//--- declare the static counter
   static int cnt=0;
//--- storing debugging data in the global variable
   com+=__FUNCSIG__+" cnt="+(string)cnt+"\n";
//--- increment the counter
   cnt++;
//--- here is some code of the function itself
  }
//+------------------------------------------------------------------+
//| Save data to file                                                |
//+------------------------------------------------------------------+
void WriteFile(string name="Отладка")
  {
//--- open the file
   ResetLastError();
   int han=FileOpen(name+".txt",FILE_WRITE|FILE_TXT|FILE_ANSI," ");
//--- check if the file has been opened
   if(han!=INVALID_HANDLE)
     {
      FileWrite(han,com); // печать данных
      FileClose(han);     // закрытие файла
     }
   else
      Print("File open failed "+name+".txt, error",GetLastError());
  }

WriteFile fonksiyonu OnDeinit içinde çağrılır. Bu nedenle programda meydana gelen tüm değişiklikler dosyaya yazılır.

Not: günlüğünüz çok büyükse bunu birkaç değişkende saklamak akıllıca olabilir. Bunu yapmanın en iyi yolu, metin değişkeninin içeriğini dize türü dizi hücresine koymak ve com değişkenini sıfırlamaktır (işin bir sonraki aşamasına hazırlık).

Bu, her 1-2 milyon dizeden sonra yapılmalıdır (tekrarlanmayan girişler). İlk olarak, değişken taşmasından kaynaklanan veri kaybını önlemiş olacaksınız (bu arada, geliştiriciler dize türü üzerinde çok çalıştığı için tüm çabalarıma rağmen bunu yapamadım). İkincisi ve en önemlisi: düzenleyicide büyük bir dosya açmak yerine verileri birkaç dosyada görüntüleyebileceksiniz.

Kaydedilen dizelerin miktarını sürekli olarak izlememek için, dosyalar ile çalışmak için fonksiyonların üç kısma ayrılmasını kullanabilirsiniz. İlk kısım dosyayı açıyor, ikincisi her yinelemede dosyaya yazıyor ve üçüncüsü dosyayı kapatıyor.

//--- open the file
int han=FileOpen("Debugging.txt",FILE_WRITE|FILE_TXT|FILE_ANSI," ");
//--- print data
if(han!=INVALID_HANDLE) FileWrite(han,com);
if(han!=INVALID_HANDLE) FileWrite(han,com);
if(han!=INVALID_HANDLE) FileWrite(han,com);
if(han!=INVALID_HANDLE) FileWrite(han,com);
//--- close the file
if(han!=INVALID_HANDLE) FileClose(han);

Ancak bu yöntem dikkatli kullanılmalıdır. Programınızın yürütülmesi başarısız olursa (örneğin, sıfıra bölüm nedeniyle), işletim sisteminizin çalışmasını bozabilecek yönetilemez bir açık dosya alabilirsiniz.

Ayrıca, her yinelemede tam aç-yaz-kapa döngüsünü kullanmanızı şiddetle tavsiye etmiyorum. Kişisel tecrübem, bu durum sabit diskinizin birkaç ay içinde öleceğinin habercisi.


5. Test Cihazı

Uzman Danışmanlarda hata ayıklarken, genellikle belirli bir koşulun aktivasyonunu kontrol etmeniz gerekir. Ancak yukarıda bahsedilen hata ayıklayıcı bir Uzman Danışmanı yalnızca gerçek zamanlı modda başlatır ve bu koşullar nihayet etkinleştirilirken oldukça uzun bir süre bekleyebilirsiniz.

Aslında, belirli alım satım koşulları nadiren ortaya çıkabilir. Ancak bunların olduğunu biliyoruz ama bunlar aylarca beklemek de saçma olur. O halde ne yapabiliriz?

strateji test cihazı bu durumda yardıma koşar. Hata ayıklama için aynı Yazdır ve Yorum fonksiyonları kullanılır. Yorum, durumu değerlendirmek için her zaman ilk sırada yer alırken daha ayrıntılı analiz için Yazdır fonksiyonu kullanılır. Test cihazı, görüntülenen verileri test cihazı günlüklerinde saklar (her test cihazı aracısı için ayrı dizin).

Bir Uzman Danışmanı doğru aralıkta başlatmak için, zamanı yerelleştiriyorum (bence hataların meydana geldiği yer), test cihazında gerekli tarihi ayarlıyorum ve bunu tüm tiklerde görselleştirme modunda başlatıyorum.

Bu hata ayıklama yöntemini MetaTrader 4'ten ödünç aldığımı da belirtmek isterim, ki bu yöntem bir programın yürütülürken sırasında hata ayıklamanın neredeyse tek yoludur.

Şekil 6. Strateji Test Cihazını kullanarak hata ayıklama

Şekil 6. Strateji Test Cihazını kullanarak hata ayıklama.


6. OOP'de Hata Ayıklama

MQL5'te ortaya çıkan nesne yönelimli programlama hata ayıklama sürecini etkilemiştir. Prosedürlerde hata ayıklarken, sadece fonksiyon adlarını kullanarak programda kolayca gezinebilirsiniz. Ancak, OOP'de, genellikle farklı yöntemlerin çağrıldığı nesneyi bilmek gerekir. Bu, nesneler dikey olarak tasarlandığında (devralma kullanılarak) özellikle önemlidir. Şablonlar (MQL5'e yakın zamanda uygulanmıştır) bu durumda yardıma koşar.

Şablon fonksiyonu, işaretçi türünün bir dize türü değeri olarak alınmasına olanak sağlar.

template<typename T> string GetTypeName(const T &t) { return(typename(T)); }

Bu özelliği hata ayıklamak için aşağıdaki şekilde kullanıyorum:

//+------------------------------------------------------------------+
//| Base class contains the variable for storing the type            |
//+------------------------------------------------------------------+
class CFirst
  {
public:
   string            m_typename; // variable for storing the type
   //--- filling the variable by the custom type in the constructor
                     CFirst(void) { m_typename=GetTypeName(this); }
                    ~CFirst(void) { }
  };
//+------------------------------------------------------------------+
//| Derived class changes the value of the base class variable       |
//+------------------------------------------------------------------+
class CSecond : public CFirst
  {
public:
   //--- filling the variable by the custom type in the constructor
                     CSecond(void) { m_typename=GetTypeName(this); }
                    ~CSecond(void) {  }
  };

Temel sınıf, türünü saklayacak değişkeni içerir (değişken, her nesnenin oluşturucusunda başlatılır). Türetilmiş sınıf, türünü saklayacak bu değişkenin değerini de kullanır. Böylece, makro çağrıldığında, sadece çağrılan fonksiyonun adını değil, aynı zamanda bu fonksiyonu çağıran nesnenin türünü de alan m_typename değişkenini ekliyorum.

İşaretçinin kendisi, nesnelerin daha doğru tanınması için türetilebilir ve kullanıcıların nesneleri sayılara göre ayırt etmesini sağlar. Bu işlem, nesne içinde şu şekilde yapılır:

Print((string)this); // print pointer number inside the class

Dışarıdayken aşağıdaki gibi görünür:

Print((string)GetPointer(pointer)); // print pointer number outside the class

Ayrıca, nesne adını saklamak için değişken her bir sınıf içinde kullanılabilir. Bu durumda, bir nesne oluştururken nesne adını oluşturucu parametresi olarak aktarmak mümkündür. Bu, nesneleri yalnızca sayılarına bölmenize değil, aynı zamanda her bir nesnenin ne anlama geldiğini (sizin adlandıracağınız şekilde) anlamanıza olanak sağlar. Bu yöntem, m_typename değişkenini doldurulmasına benzer şekilde gerçekleştirilebilir.


7. İzleme

Yukarıda bahsedilen tüm yöntemler birbirini tamamlar ve hata ayıklama için çok önemlidir. Ancak, çok popüler olmayan başka bir yöntem daha var: izleme.

Bu yöntem, karmaşıklığı nedeniyle nadiren kullanılır. Takılıp kaldığınızda ve neler olduğunu anlamadığınızda, izleme size yardımcı olabilir.

Bu yöntem, uygulamanın yapısını - çağrıların sırasını ve nesnelerini - anlamanıza olanak tanır. İzlemeyi kullanarak programda neyin yanlış olduğunu anlayacaksınız. Ayrıca, yöntem projeye genel bir bakış sağlar.

İzleme şu şekilde yapılır. İki makro oluşturun:

//--- opening substitution  
#define zx Print(__FUNCSIG__+"{");
//--- closing substitution
#define xz Print("};");

Bunlar sırasıyla açılış zx ve kapanış xz makrolarıdır. Bunları, izlenecek fonksiyon gövdelerine yerleştirelim:

//+------------------------------------------------------------------+
//| Example of function tracing                                      |
//+------------------------------------------------------------------+
void myfunc(int a,int b)
  {
   zx
//--- here is some code of the function itself
   if(a!=b) { xz return; } // exit in the middle of the function
//--- here is some code of the function itself
   xz return;
  }

Eğer fonksiyon şartlara göre çıkış içeriyorsa, her dönüşten önce korunan alanda xz kapanışını ayarlamalıyız. Bu, izleme yapısının bozulmasını önleyecektir.

Yukarıda bahsedilen makronun sadece örneği basitleştirmek için kullanıldığını unutmayın. İzleme için dosyaya yazdırmayı kullanmak daha iyidir. Ayrıca, dosyaya yazdırırken bir hile kullanıyorum. Tüm izleme yapısını görmek için fonksiyon adlarını aşağıdaki söz dizimsel yapıya sarıyorum:

if() {...}

Ortaya çıkan dosya, bunun MetaEditor'da açılmasını sağlayan ".mqh" uzantısı ile ve izleme yapısını göstermek için biçimlendirici [Ctrl+,] kullanılarak ayarlanır.

Tam izleme kodu aşağıda gösterilmiştir:

string com=""; // declare global variable for storing debugging data
//--- opening substitution
#define zx com+="if("+__FUNCSIG__+"){\n";
//--- closing substitution
#define xz com+="};\n"; 
//+------------------------------------------------------------------+
//| Program shutdown                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- //--- saving data to the file when closing the program
   WriteFile();
  }
//+------------------------------------------------------------------+
//| Example of the function tracing                                  |
//+------------------------------------------------------------------+
void myfunc(int a,int b)
  {
   zx
//--- here is some code of the function itself
   if(a!=b) { xz return; } // exit in the middle of the function
//--- here is some code of the function itself
   xz return;
  }
//+------------------------------------------------------------------+
//| Save data to file                                                |
//+------------------------------------------------------------------+
void WriteFile(string name="Tracing")
  {
//--- open the file
   ResetLastError();
   int han=FileOpen(name+".mqh",FILE_WRITE|FILE_TXT|FILE_ANSI," ");
//--- check if the file has opened
   if(han!=INVALID_HANDLE)
     {
      FileWrite(han,com); // print data
      FileClose(han);     // close the file
     }
   else
      Print("File open failed "+name+".mqh, error",GetLastError());
  }

Belirli bir yerden izlemeye başlamak için makrolar koşullar ile desteklenmelidir:

bool trace=0; // variable for protecting tracing by condition
//--- opening substitution
#define zx if(trace) com+="if("+__FUNCSIG__+"){\n";
//--- closing substitution
#define xz if(trace) com+="};\n";

Bu durumda, belirli bir olaydan sonra veya belirli bir yerde "true" veya "false" değerini "trace" değişkenine ayarladıktan sonra izlemeyi etkinleştirebilir veya devre dışı bırakabilirsiniz.

Daha sonra gerekli olabileceği halde izleme o anda gerekli değilse veya o anda kaynağı temizlemek için yeterli zaman yoksa, makro değerleri boş değerlerle değiştirilerek devre dışı bırakılabilir:

//--- substitute empty values
#define zx
#define xz

İzleme için değişiklikleri içeren standart Uzman Danışmanın bulunduğu dosya aşağıya eklenmiştir. İzleme sonuçları, grafikte Uzman Danışmanı başlattıktan sonra Files (Dosyalar) dizininde görülebilir (tracing.mqh dosyası oluşturulur). Ortaya çıkan dosyanın metninden metin parçası şudur:

if(int OnInit()){
};
if(void OnTick()){
if(void CheckForOpen()){
};
};
if(void OnTick()){
if(void CheckForOpen()){
};
};
if(void OnTick()){
if(void CheckForOpen()){
};
};
//--- ...

İç içe çağrıların yapısının başlangıçta yeni oluşturulan dosyada açıkça tanımlanamayacağını, ancak kod biçimlendiriciyi kullandıktan sonra bunun tüm yapısını görebileceğinizi unutmayın. Aşağıda, biçimlendirici kullanıldıktan sonra ortaya çıkan dosyanın metni yer almaktadır:

if(int OnInit())
  {
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if(void OnTick())
  {
   if(void CheckForOpen())
     {
     };
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if(void OnTick())
  {
   if(void CheckForOpen())
     {
     };
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
if(void OnTick())
  {
   if(void CheckForOpen())
     {
     };
  };
//--- ...

Bu sadece benim hilem ve izlemenin nasıl yapılması gerektiğine dair bir örnek değil. Herkes izlemeyi kendi yöntemiyle yapmakta özgür. Ana konu, izlemenin fonksiyon çağrılarının yapısını ortaya çıkarmasıdır.


Hata Ayıklamaya Dair Önemli Not

Hata ayıklama sırasında kodunuzda değişiklikler uygularsanız, doğrudan MQL5 fonksiyonlarının çağrılarını sarmayı kullanın. Nasıl yapıldığı aşağıda açıklanmıştır:

//+------------------------------------------------------------------+
//| Example of wrapping a standard function in a shell function      |
//+------------------------------------------------------------------+
void DebugPrint(string text) { Print(text); }

Bu, hata ayıklama tamamlandığında kodu kolayca temizlemenizi sağlar:

  • "DebugPrint" fonksiyon çağrısını kaldırın,
  • sonra derleyin
  • bu fonksiyonun çağrılarını MetaEditor'ın derleme hatalarına dair uyarı verdiği satırlarda derleyin ve silin.

Aynısı hata ayıklamada kullanılan değişkenler için de geçerlidir. Bu nedenle, global olarak bildirilen değişkenleri ve fonksiyonları kullanmayı deneyin. Bu, sizi, uygulamanızın derinliklerinde kaybolan yapıları aramaktan kurtaracaktır.


Sonuç

Hata ayıklama, programcının işinin önemli bir parçasıdır. Program hata ayıklaması yapamayan kişiye programcı denilemez. Ancak ana hata ayıklama her zaman kafanızda gerçekleştirilir. Bu makale yalnızca hata ayıklamada kullanılan bazı yöntemleri gösterir. Ancak uygulamanın çalışma prensipleri anlaşılmadan bu yöntemler hiçbir işe yaramayacaktır.

Başarılı hata ayıklamalar diliyorum!

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/654

Ekli dosyalar |
Nokta ve Şekil Grafiği Oluşturma için Gösterge Nokta ve Şekil Grafiği Oluşturma için Gösterge
Mevcut piyasa durumuna dair bilgi sağlayan birçok grafik türü vardır. Nokta ve Şekil grafiği gibi birçoğu uzak geçmişten mirastır. Makale, gerçek zamanlı bir gösterge kullanarak Nokta ve Şekil grafiği oluşturmanın bir örneğini açıklanmaktadır.
MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma
Hangi alım satım stratejisini kullanırsanız kullanın, gelecekteki kârları sağlamak için hangi parametreleri seçeceğinize dair her zaman bir soru olacaktır. Bu makale, aynı anda birçok sembol parametresini optimize etme imkanına sahip bir Uzman Danışman örneği sağlar. Bu yöntemin, aşırı öğrenme parametrelerin etkisini azaltması ve çalışma için tek bir sembolden elde edilen verilerin yeterli olmadığı durumları ele alması amaçlanır.
MQL5 Cloud Network: Hala Hesaplıyor musunuz? MQL5 Cloud Network: Hala Hesaplıyor musunuz?
Yakında MQL5 Cloud Network'ün piyasaya sürülmesinden bu yana bir buçuk yıl geçmiş olacak. Bu öncü olay, yeni bir algoritmik alım satım çağını başlattı - şimdi birkaç tıklamayla, yatırımcıların emrinde alım satım stratejilerinin optimizasyonu için yüzlerce ve binlerce bilgi işlem çekirdeği olabilir.
MQL5 Tarif Defteri Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma MQL5 Tarif Defteri Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma
Çeşitli forumlarda iletişim kurarken, sık sık Microsoft Excel grafiklerinin ekran görüntüsü olarak görüntülenen test sonuçlarımın örneklerini kullandım. Bu tür grafiklerin nasıl oluşturulabileceğini açıklamam birçok kez istendi. Son olarak, şimdi bu makalede her şeyi açıklamak için biraz zamanım var.