日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

MQL4程序的常見錯誤以及如何避免它們

 寒木蕭條 2016-08-17

介紹

一些較舊的程序可能在新版本的MQL4編譯器中返回錯誤。

為了避免關(guān)鍵的程序完成,以前版本的編譯器在運行環(huán)境中處理了許多錯誤。例如,除數(shù)為零或數(shù)組越界都是嚴重錯誤,并通常會導致應用程序崩潰。這些錯誤只在一些狀態(tài)下針對某些變量值而發(fā)生。閱讀這篇文章了解如何處理這樣的情況。 

新的編譯器可以檢測實際或潛在的錯誤源并提高代碼質(zhì)量。

在這篇文章中,我們討論了舊程序編譯過程中檢測到的可能出現(xiàn)的錯誤,以及解決這些問題的方法。

  1. 編譯錯誤
  2. 運行時間錯誤
  3. 編譯器警告

1編譯錯誤

如果程序代碼中包含錯誤,則它不能被編譯。

要完全控制所有的錯誤,建議使用嚴謹?shù)木幾g模式,它通過以下指令來設(shè)置:

#property strict

這種模式大大簡化了故障排除。 


1.1. 與關(guān)鍵字一致的標識

如果變量或函數(shù)的名稱與其中一個關(guān)鍵字一致

int char[];  // incorrect
int char1[]; // correct
int char()   // incorrect
{
 return(0);
}

編譯器會返回一個錯誤信息:

圖1. 錯誤“unexpected token(非預期標記)”和“name expected(預期名稱)”

圖1. 錯誤“unexpected token(非預期標記)”和“name expected(預期名稱)”

要解決這個錯誤,您需要使用變量或函數(shù)的正確名稱。


1.2. 變量和函數(shù)名的特殊字符

如果變量或函數(shù)名稱中包含特殊字符($,@,點): 

int $var1; // incorrect
int @var2; // incorrect 
int var.3; // incorrect
void f@()  // incorrect
{
 return;
}

編譯器會返回一個錯誤信息:

圖2. 錯誤“unknown symbol(未知交易品種)”與“semicolon expected(預期分號)”

圖2. 錯誤“unknown symbol(未知交易品種)”與“semicolon expected(預期分號)”

要解決這個錯誤,您需要使用正確的函數(shù)或變量名。


1.3. 使用switch操作符的錯誤

在舊版本的編譯器中,您可以在switch操作符的表達式和常量中使用任何值:

void start()
  {
   double n=3.14;
   switch(n)
     {
      case 3.14: Print("Pi");break;
      case 2.7: Print("E");break;
     }
  }

在新的編譯器中,switch操作符的常量和表達式必須是整數(shù),所以當您嘗試使用這樣的結(jié)構(gòu)時會發(fā)生錯誤:

圖3. 錯誤“illegal switch expression type(非法switch表達式類型)”和“constant expression is not integral(常量表??達式不是整數(shù))”

圖3. 錯誤“illegal switch expression type(非法switch表達式類型)”和“constant expression is not integral(常量表??達式不是整數(shù))”

在這種情況下,您可以使用明確的數(shù)值比較,例如:

void start()
  {
   double n=3.14;
   if(n==3.14) Print("Pi");
   else
      if(n==2.7) Print("E");
  }

1.4. 函數(shù)返回值

除了空值外的所有函數(shù)都應該返回聲明的類型值。例如:

int function()
{
}

在嚴謹?shù)木幾g模式下發(fā)生錯誤:


圖4. 錯誤“not all control paths return a value(并非所有的控制路徑返回一個值)”

圖4. 錯誤“not all control paths return a value(并非所有的控制路徑返回一個值)”

在默認的編譯模式下,編譯器會返回一個警告:

圖5. 警告:“not all control paths return a value(并非所有的控制路徑返回一個值)”

圖5. 警告:“not all control paths return a value(并非所有的控制路徑返回一個值)”

如果函數(shù)的返回值與聲明的不匹配:

int init()                         
  {
   return;                          
  }

在嚴格的編譯中會檢測錯誤:

圖6. 錯誤“function must return a value(函數(shù)必須返回一個值)”

圖6. 錯誤“function must return a value(函數(shù)必須返回一個值)”

在默認的編譯模式下,編譯器會返回一個警告:

圖7. 警告 'return - function must return a value(回報 - 函數(shù)必須返回一個值)”

圖7. 警告 'return - function must return a value(回報 - 函數(shù)必須返回一個值)”

要解決這樣的錯誤,添加帶有相應類型返回值的return操作符到函數(shù)代碼。



1.5. 函數(shù)參數(shù)數(shù)組

在函數(shù)參數(shù),數(shù)組現(xiàn)在只引用傳遞。 

double ArrayAverage(double a[])
{
 return(0);
}
在嚴謹?shù)木幾g模式下,該代碼將導致錯誤:

圖8. 編譯器錯誤“arrays passed by reference only(數(shù)組只引用傳遞)”

圖8. 編譯器錯誤“arrays passed by reference only(數(shù)組只引用傳遞)”

在默認的編譯模式下,編譯器會返回一個警告:

圖9. 編譯器警告“arrays passed by reference only(數(shù)組只引用傳遞)”

圖9. 編譯器警告“arrays passed by reference only(數(shù)組只引用傳遞)”

要修復此錯誤,您必須通過在數(shù)組名稱之前添加前綴來指定數(shù)組是通過引用傳遞的:

double ArrayAverage(double &a[])
{
 return(0);
}

但應注意的是,現(xiàn)在常量數(shù)組 (Time[]Open[]High[]Low[]Close[]Volume[]) 不能引用傳遞。例如,下面的調(diào)用:

ArrayAverage(Open);

無論何種編譯模式都會導致錯誤:

圖10. 錯誤'Open' - constant variable cannot be passed as reference(‘打開’ - 常量變量不能引用傳遞)

圖10. 錯誤'Open' - constant variable cannot be passed as reference(‘打開’ - 常量變量不能引用傳遞)

為了避免這些錯誤,從常量數(shù)組??復制所需的數(shù)據(jù):

   //--- an array that stores open price values
   double OpenPrices[];
   //--- copy the values of open prices to the OpenPrices[] array
   ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY);
   //--- function call
   ArrayAverage(OpenPrices);



2. 運行時間錯誤

程序代碼執(zhí)行過程中出現(xiàn)的錯誤稱為運行時間錯誤。這種錯誤通常是依賴于程序的狀態(tài),并與變量的不正確的值相關(guān)聯(lián)。 

例如,如果變量用作數(shù)組元素的索引,其負值將不可避免地導致數(shù)組超出范圍的錯誤。


2.1. 數(shù)組超出范圍

訪問指標緩沖區(qū)時常常在指標中發(fā)生這個錯誤。該IndicatorCounted()函數(shù)返回自上次指標調(diào)用的不變的柱數(shù)。先前計算的柱的指標值不需要重新計算,所以為了更快的計算,您只需要處理最后的幾個柱。 

大部分使用這種計算優(yōu)化的方法的指標看起來如下:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   //--- some calculations require no less than N bars (e.g. 100)      
   if (Bars<100) // if less bars are available on a chart (for example on MN timeframe)    
     return(-1); // stop calculation and exit

   //--- the number of bars that have not changed since the last indicator call
   int counted_bars=IndicatorCounted();
   //--- exit if an error has occurred
   if(counted_bars<0) return(-1);
      
   //--- position of the bar from which calculation in the loop starts
   int limit=Bars-counted_bars;

   //--- if counted_bars=0, reduce the starting position in the loop by 1,   
   if(counted_bars==0) 
     {
      limit--;  // to avoid the array out of range problem when counted_bars==0
      //--- we use a shift of 10 bars back in history, so add this shift during the first calculation
      limit-=10;
     }
   else //--- the indicator has been already calculated, counted_bars>0
     {     
      //--- for repeated calls increase limit by 1 to update the indicator values for the last bar
      limit++;
     } 
   //--- the main calculation loop
   for (int i=limit; i>0; i--)
   {
     Buff1[i]=0.5*(Open[i+5]+Close[i+10]) // values of bars 5 and 10 bars deeper to history are used
   }
}

通常counted_bars==0的情況處理不當(初始限制持倉應該通過等于相對循環(huán)變量的1 +最大指數(shù)的值來降低)。

另外,請記住,在執(zhí)行start()函數(shù)的時候,我們可以從0到Bars ()-1的訪問指標緩沖區(qū)的數(shù)組元素。如果您需要使用無指標緩沖區(qū)的數(shù)組,那么按照指標緩沖區(qū)的當前大小使用ArrayResize()函數(shù)來增加其大小。也可以通過調(diào)用用作參數(shù)的指標緩沖區(qū)的 ArraySize()來獲得元素地址的最大指數(shù)。


2.2. 除數(shù)為零

當除法運算中除數(shù)為零時則會發(fā)生零除的錯誤:

void OnStart()
  {
//---
   int a=0, b=0,c;
   c=a/b;
   Print("c=",c);
  }

當您運行這個腳本時,專家選項卡會出現(xiàn)一條錯誤的消息,并且程序關(guān)閉:

圖11. 錯誤消息“zero divide(除數(shù)為零)”

圖11. 錯誤消息“zero divide(除數(shù)為零)”

當除數(shù)的值由任何外部數(shù)據(jù)值來決定時,通常會出現(xiàn)此錯誤。例如,如果交易參數(shù)進行分析,如果沒有新建訂單,那么已用預付款的值等于0。另一個例子:如果要從一個文件讀取分析數(shù)據(jù),如果該文件不可用,那么我們也不能保證正確的操作。所以您應該考慮到這樣的情況并正確地處理它們。

最簡單的方法是除法運算前檢查除數(shù)并報告不正確的參數(shù)值:

void OnStart()
  {
//---
   int a=0, b=0,c;
   if(b!=0) {c=a/b; Print(c);}
   else {Print("Error: b=0"); return; };
  }

這不會導致嚴重的錯誤,但是不正確參數(shù)值的消息一出現(xiàn)則程序即關(guān)閉:

圖12. 不正確的除數(shù)消息

圖12. 不正確的除數(shù)消息


2.3. 當前字符用0替代NULL 

在舊版本的編譯器中0(零)可用作滿足金融工具規(guī)范的函數(shù)參數(shù)。

例如,當前交易品種的移動平均線技術(shù)指標的值可能被要求如下:

AlligatorJawsBuffer[i]=iMA(0,0,13,8,MODE_SMMA,PRICE_MEDIAN,i);    // incorrect

在新的編譯器中您應該明確地指定NULL來規(guī)定當前的交易品種:

AlligatorJawsBuffer[i]=iMA(NULL,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // correct

此外,當前交易品種和圖表周期可使用Symbol()Period()函數(shù)來指定。

AlligatorJawsBuffer[i]=iMA(Symbol(),Period(),13,8,MODE_SMMA,PRICE_MEDIAN,i); // correct


2.4. Unicode字符串和它們在DLL中的使用

字符串現(xiàn)在表示為Unicode字符序列。

記住這一點,并使用適當?shù)腤indows函數(shù)。例如,使用wininet.dll庫來替代 InternetOpenA() 和InternetOpenUrlA(),您應該調(diào)用InternetOpenW() 和InternetOpenUrlW()。

字符串的內(nèi)部結(jié)構(gòu)在MQL4中(現(xiàn)在只需要12個字節(jié))發(fā)生了變化,當傳遞字符串到DLL時應使用MqlString結(jié)構(gòu):

#pragma pack(push,1)
struct MqlString
  {
   int      size;       // 32 bit integer, contains the size of the buffer allocated for the string
   LPWSTR   buffer;     // 32 bit address of the buffer that contains the string
   int      reserved;   // 32 bit integer, reserved, do not use
  };
#pragma pack(pop,1)


2.5. 文件共享

在新MQL4中,F(xiàn)ILE_SHARE_WRITE和FILE_SHARE_READ標志應明確地指定以便打開文件時共享使用。 

如果標志不存在,那么該文件以單獨模式打開,直到文件由打開它的用戶關(guān)閉才可以被其他人打開。

例如,使用離線圖表時共享標志應明確指定:

   // 1-st change - add share flags
   ExtHandle=FileOpenHistory(c_symbol+i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);

欲了解更多詳情,請閱讀新MQL4的離線圖表。


2.6. 日期時間轉(zhuǎn)換

轉(zhuǎn)換日期時間為一個字符串現(xiàn)在取決于編譯模式:

  datetime date=D'2014.03.05 15:46:58';
  string str="mydate="+date;
//--- str="mydate=1394034418" - old compiler, no directive #property strict in the new compiler
//--- str="mydate=2014.03.05 15:46:58" - new compiler with the directive #property strict

例如,嘗試使用文件名中包含冒號的文件會導致錯誤。


3. 編譯器警告

編譯器警告是信息性而非錯誤的訊息,但它們指出了可能的錯誤來源。

一個清晰的代碼不應該包含警告。


3.1. 全局和局部變量名稱一致

如果全局和局部各級變量具有相似的名稱:

int i; // a global variable
void OnStart()
  {
//---
   int i=0,j=0; // local variables
   for (i=0; i<5; i++) {j+=i;}
   PrintFormat("i=%d, j=%d",i,j);
  }

編譯器會顯示指出全局變量的聲明行號的警告:

圖13. 警告“declaration of '%' hides global declaration at line %(聲明'%'隱藏在行%的全局聲明)”

圖13. 警告“declaration of '%' hides global declaration at line %(聲明'%'隱藏在行%的全局聲明)”

要解決這樣的警告需要修正全局變量的名稱。


3.2. 類型不匹配

新的編譯器有一個新的類型轉(zhuǎn)換操作。

#property strict
void OnStart()
  {
   double a=7;
   float b=a;
   int c=b;
   string str=c;
   Print(c);
  }

在嚴謹?shù)木幾g模式下如果類型不匹配則編譯器會顯示警告:

Figure 14. Warnings "possible loss of data due to type conversion" and "implicit conversion from 'number' to 'string'

圖14. 警告“possible loss of data due to type conversion(由于類型轉(zhuǎn)換可能丟失數(shù)據(jù))”和“implicit conversion from 'number' to 'string'(從'數(shù)字'到'字符串'的隱式轉(zhuǎn)換)”

在這個示例中,編譯器警告關(guān)于分配的不同數(shù)據(jù)類型的可能的精確度損失和從整數(shù)到字符串的隱式轉(zhuǎn)換。

要解決此警告需要使用明確的類型轉(zhuǎn)換:

#property strict
void OnStart()
  {
   double a=7;
   float b=(float)a;
   int c=(int)b;
   string str=(string)c;
   Print(c);
  }

3.3. 未使用的變量

程序代碼中存在不使用的變量(多余的實體)不是一個好習慣。

void OnStart()
  {
   int i,j=10,k,l,m,n2=1;
   for(i=0; i<5; i++) {j+=i;}
  }

無論何種編譯模式都會顯示這些變量的報告:

圖15. 警告“variable '%' not used('%'變量未使用)”

圖15. 警告“variable '%' not used('%'變量未使用)”

要修復它,需要從代碼中移除未使用的變量。


結(jié)論

本文描述了包含錯誤的舊程序的編譯過程中可能出現(xiàn)的常見問題。

在所有情況下,建議使用嚴謹?shù)木幾g模式來調(diào)試程序。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多