
通过注释确定代码中错误的方法
简介
本文介绍了在 MQL 代码中搜索错误的简单算法。由于代码错误导致的编译问题经常在编写程序后出现。错误类型可能各种各样,但无论如何,有必要快速识别发生错误的代码块。
通常,人们花费大量时间和精力搜索一些多余的括号。但是,有一种方法可以利用注释快速定位错误。这就是我要在本文讲述的方法。
概念
编写大段代码而不出现错误自然很好。但不幸的是这并不经常出现。甚至有人笑称,不存在没有错误的程序。这里我所说的并非是导致代码执行错误的错误。而是导致无法编译的错误。
非常普遍的错误有:在复杂条件中插入一个多余括号、缺少括号、没有写冒号以及逗号(在声明变量时)等。通常我们可以在编译时立即看出哪一个条目包含错误。但有时候没那么容易发现这种错误。无论是编译器还是好眼力都无法帮我们立即发现错误。在这种情况下,编程新手(以及非新手)通常开始浏览所有代码,试图凭目力找出错误。屡次三番,精力耗尽,感叹道:“重新编写倒更容易一些”!
但是,跟其他编程语言一样,MQL 也提供了一个非常好的工具 - 注释。你可以用它“移除”、“禁用”一些代码部分。通常,这种评论用于插入注释,或禁用代码的未使用部分。评论也可以成功用于搜索错误。
搜索错误的算法
搜索错误通常用于确定发生错误的代码部分,然后在其中以目力搜索出错误。检查 5-10 条代码跟 100-150 条代码相比,“使用肉眼”显然更加容易和快捷。
使用注释可以使问题迎刃而解。首先,需要注释代码的一些不同部分(有时几乎是整个代码),将其“禁用”。然后从代码的那些部分移除注释。在对注释进行正常移除后,尝试编译代码。如果编译成功,说明错误不在这部分代码内。然后打开另一部分代码,以此类推。当发现代码的问题部分后,进行目力找出并纠正。再次尝试进行编译。如果一切成功通过,说明错误已经消除。
如果出现新错误,则重复以上步骤直到错误完全消除。该方法在编写大型程序时非常有用,在编写相对较小的代码时较少使用。
正确的确定要注释的代码块非常重要。如果它是一个条件(或另一个逻辑结构),则应该完全注释。如果注释了声明变量的代码块,则注意务必闭合涉及这些变量的代码块。也就是说注释应该按照编程逻辑使用。违反该方式将导致编译时出现新的误报错误。
示例
我将以在代码中实际搜索错误为例。假设我们有以下代码:
#property copyright "" #property link "" extern int Level1=6; extern int Level2=2; extern double Lots=0.1; extern int TP=7; extern int SL=5000; extern int Profit_stop=10; int start() { //+--------------------------------------------------------------------------------------------------+ //| search for opened orders by symbol int pos_sell=0; for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--) { if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL) &&(OrderComment()=="sar_ao")) { pos_sell=1; break; } } int pos_buy=0; for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--) { if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY) &&(OrderComment()=="sar_ao")) { pos_buy=1; break; } } //| search for opened orders by symbol | //+-------------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------------+ //| stop for break-even double stop_open; for (int ia=OrdersTotal()-1; ia>=0; ia--) { if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break; if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } } //| stop for break-even | //+-------------------------------------------------------------------------------------------------+ int i; bool trend_UP=true,trend_DOWN=true; //+------------------------------------------------------------------------------- if(!pos_buy) { for(i=Level1; i>=0; i--) { if(Open[i]<iSAR(NULL,0,0.02,0.1,i)) { trend_UP=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_UP=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_UP=false; break; } } } } else { trend_UP=false; } //*************************************************************************** if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; } if(Open[0]>iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("sell"); } if(Open[0]<iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("buy"); } double MA_1; MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0) { OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT); ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen); } if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0) { OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red); ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT); ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("sell", OBJPROP_COLOR, Red); } //+------------------------------------------------------------------------------- //---- return(0); } //+------------------------------------------------------------------+
在编译时我们发现了以下错误信息:
无法快速检测到发生错误的代码块。我们求助于注释。对所有逻辑结构进行注释:
#property copyright "" #property link "" extern int Level1=6; extern int Level2=2; extern double Lots=0.1; extern int TP=7; extern int SL=5000; extern int Profit_stop=10; int start() { /* //+-----------------------------------------------------------------------------------------------+ //| search for opened orders by symbol | int pos_sell=0; for (int i_op_sell=OrdersTotal()-1; i_op_sell>=0; i_op_sell--) { if (!OrderSelect(i_op_sell,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_SELLSTOP||OrderType()==OP_SELL) &&(OrderComment()=="sar_ao")) { pos_sell=1; break; } } int pos_buy=0; for (int i_op_buy=OrdersTotal()-1; i_op_buy>=0; i_op_buy--) { if (!OrderSelect(i_op_buy,SELECT_BY_POS,MODE_TRADES)) break; if (Symbol()==OrderSymbol()&&(OrderType()==OP_BUYSTOP||OrderType()==OP_BUY) &&(OrderComment()=="sar_ao")) { pos_buy=1; break; } } //| search for opened orders by symbol | //+----------------------------------------------------------------------------------------------+ */ /* //+----------------------------------------------------------------------------------------------+ //| stop for break-even | double stop_open; for (int ia=OrdersTotal()-1; ia>=0; ia--) { if (!OrderSelect(ia,SELECT_BY_POS,MODE_TRADES)) break; if ((OrderType()==OP_BUY)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (NormalizeDouble(Bid,Digits)-stop_open<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()+1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } if ((OrderType()==OP_SELL)&&(Symbol()==OrderSymbol())&&(OrderComment()=="sar_ao")) { stop_open=OrderOpenPrice(); if (stop_open-NormalizeDouble(Ask,Digits)<=Profit_stop*Point) continue; OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-1*Point,OrderTakeProfit(), OrderExpiration(),CLR_NONE); } } //| stop for break-even | //+---------------------------------------------------------------------------------------------+ */ /* int i; bool trend_UP=true,trend_DOWN=true; //+------------------------------------------------------------------------------- if(!pos_buy) { for(i=Level1; i>=0; i--) { if(Open[i]<iSAR(NULL,0,0.02,0.1,i)) { trend_UP=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_UP=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_UP=false; break; } } } } else { trend_UP=false; } */ //*************************************************************************** /* if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; } */ /* if(Open[0]>iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("sell"); } if(Open[0]<iSAR(NULL,0,0.02,0.2,0)) { ObjectDelete("buy"); } */ double MA_1; MA_1=iStochastic(NULL,0,5,3,3,MODE_SMA,0,MODE_SIGNAL,0); /* if(trend_UP && MA_1<50 && Open[1]<Close[1] && !pos_buy && ObjectFind("buy") != 0) { OrderSend(Symbol(),OP_BUY, Lots,Ask,2,Ask-SL*Point,Ask+TP*Point,"sar_ao",0,0,Blue); ObjectCreate("buy", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("buy", OBJPROP_STYLE, STYLE_DOT); ObjectSet("buy", OBJPROP_ARROWCODE, SYMBOL_ARROWUP); ObjectSet("buy", OBJPROP_COLOR, LightSeaGreen); } */ /* if(trend_DOWN && MA_1>50 && Open[1]>Close[1] && !pos_sell && ObjectFind("sell") != 0) { OrderSend(Symbol(),OP_SELL, Lots,Bid,2,Bid+SL*Point,Bid-TP*Point,"sar_ao",0,0,Red); ObjectCreate("sell", OBJ_ARROW, 0, Time[0], Bid); ObjectSet("sell", OBJPROP_STYLE, STYLE_DOT); ObjectSet("sell", OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN); ObjectSet("sell", OBJPROP_COLOR, Red); } */ //+------------------------------------------------------------------------------- //---- return(0); } //+------------------------------------------------------------------+
你可以轻松确保该代码可以毫无问题的编译。这意味着发生错误的代码部分被“隐藏”了。轮流打开代码 /* ...*/ 的部分并尝试编译。
直到下面的代码块之前,编译都很成功:
//*************************************************************************** if(!pos_sell) { for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } } for(i=Level2*2; i>=0; i--) { if(i>Level2) { if(iAO(NULL, 0, i+1)>=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } if(i<Level2) { if(iAO(NULL, 0, i+1)<=iAO(NULL, 0, i)) { trend_DOWN=false; break; } } } } else { trend_DOWN=false; }
因此,错误位于该逻辑结构内。在对该代码部分进行详细检查后,我们可以看到结构内有多余的圆括号:
for(i=Level1; i>=0; i--) { { if(Open[i]>iSAR(NULL,0,0.02,0.1,i)) { trend_DOWN=false; break; } }
如果将其移除,就可以成功编译代码。
通过移除剩余的注释,就可以确定代码中没有其他错误了。说明我们实现了目标 - 即快速找出代码中的错误。
总结
通过一个实际示例演示了如何使用该算法来搜索错误。本例中使用的代码并不小(194 条),所以其“调查”要花费一些时间。当遇到搜索错误的问题时,注释的可能性本身就为程序员节省了大量时间。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1547
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.

