小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 寒木蕭條 2016-08-17

介紹

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

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

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

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

  1. 編譯錯(cuò)誤
  2. 運(yùn)行時(shí)間錯(cuò)誤
  3. 編譯器警告

1編譯錯(cuò)誤

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

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

#property strict

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


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

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

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

編譯器會(huì)返回一個(gè)錯(cuò)誤信息:

圖1. 錯(cuò)誤“unexpected token(非預(yù)期標(biāo)記)”和“name expected(預(yù)期名稱)”

圖1. 錯(cuò)誤“unexpected token(非預(yù)期標(biāo)記)”和“name expected(預(yù)期名稱)”

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


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

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

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

編譯器會(huì)返回一個(gè)錯(cuò)誤信息:

圖2. 錯(cuò)誤“unknown symbol(未知交易品種)”與“semicolon expected(預(yù)期分號(hào))”

圖2. 錯(cuò)誤“unknown symbol(未知交易品種)”與“semicolon expected(預(yù)期分號(hào))”

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


1.3. 使用switch操作符的錯(cuò)誤

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

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

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

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

圖3. 錯(cuò)誤“illegal switch expression type(非法switch表達(dá)式類型)”和“constant expression is not integral(常量表??達(dá)式不是整數(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ù)都應(yīng)該返回聲明的類型值。例如:

int function()
{
}

在嚴(yán)謹(jǐn)?shù)木幾g模式下發(fā)生錯(cuò)誤:


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

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

在默認(rèn)的編譯模式下,編譯器會(huì)返回一個(gè)警告:

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

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

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

int init()                         
  {
   return;                          
  }

在嚴(yán)格的編譯中會(huì)檢測錯(cuò)誤:

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

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

在默認(rèn)的編譯模式下,編譯器會(huì)返回一個(gè)警告:

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

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

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



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

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

double ArrayAverage(double a[])
{
 return(0);
}
在嚴(yán)謹(jǐn)?shù)木幾g模式下,該代碼將導(dǎo)致錯(cuò)誤:

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

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

在默認(rèn)的編譯模式下,編譯器會(huì)返回一個(gè)警告:

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

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

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

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

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

ArrayAverage(Open);

無論何種編譯模式都會(huì)導(dǎo)致錯(cuò)誤:

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

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

為了避免這些錯(cuò)誤,從常量數(shù)組??復(fù)制所需的數(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. 運(yùn)行時(shí)間錯(cuò)誤

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

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


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

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

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

//+------------------------------------------------------------------+
//| 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的情況處理不當(dāng)(初始限制持倉應(yīng)該通過等于相對循環(huán)變量的1 +最大指數(shù)的值來降低)。

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


2.2. 除數(shù)為零

當(dāng)除法運(yùn)算中除數(shù)為零時(shí)則會(huì)發(fā)生零除的錯(cuò)誤:

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

當(dāng)您運(yùn)行這個(gè)腳本時(shí),專家選項(xiàng)卡會(huì)出現(xiàn)一條錯(cuò)誤的消息,并且程序關(guān)閉:

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

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

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

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

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

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

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

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


2.3. 當(dāng)前字符用0替代NULL 

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

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

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

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

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

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

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


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

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

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

字符串的內(nèi)部結(jié)構(gòu)在MQL4中(現(xiàn)在只需要12個(gè)字節(jié))發(fā)生了變化,當(dāng)傳遞字符串到DLL時(shí)應(yīng)使用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標(biāo)志應(yīng)明確地指定以便打開文件時(shí)共享使用。 

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

例如,使用離線圖表時(shí)共享標(biāo)志應(yīng)明確指定:

   // 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. 日期時(shí)間轉(zhuǎn)換

轉(zhuǎn)換日期時(shí)間為一個(gè)字符串現(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

例如,嘗試使用文件名中包含冒號(hào)的文件會(huì)導(dǎo)致錯(cuò)誤。


3. 編譯器警告

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

一個(gè)清晰的代碼不應(yīng)該包含警告。


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

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

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);
  }

編譯器會(huì)顯示指出全局變量的聲明行號(hào)的警告:

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

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

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


3.2. 類型不匹配

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

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

在嚴(yán)謹(jǐn)?shù)木幾g模式下如果類型不匹配則編譯器會(huì)顯示警告:

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)換)”

在這個(gè)示例中,編譯器警告關(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. 未使用的變量

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

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

無論何種編譯模式都會(huì)顯示這些變量的報(bào)告:

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

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

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


結(jié)論

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

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

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

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多