1.なぜマクロなのか?マクロは不便だし、すべての条件を入力できるわけではない。些細なプロシージャを実装する方が簡単だった。
2.配列の "汚いトリック"。ゼロで割ることはできないのか?
1.なぜマクロなのか?マクロは不便だし、すべての条件を入力できるわけではない。些細なプロシージャを実装する方が簡単だった。
2.配列の "汚いトリック"。ゼロで割ることはできないのか?
1.根拠のない話にならないように、私のマクロに与えられない条件の例を示してください(皮肉ではなく、このマクロをいつも使っている私にとって、微妙な点をすべて知ることは本当に重要なのです)。では、デバッグの難しさを教えてください。
一般的には、はい、プロシージャを使えばできます。しかし、公正を期すために、私はプロシージャでこのデータをすべて取得する優雅な方法を知りません:
- チェックに渡される式のテキスト(#condition)。
- マクロが呼び出されたソースコードのファイル名(__FILE__)。
- マクロが呼び出された関数またはメソッドのシグネチャ(__FUNCSIG__)。
- マクロが呼び出されたソースコードファイルの行番号(__LINE__)。
これらすべてを実装するプロシージャ(もちろん、"out of the box "であり、マシン上であり、手動でこれらすべてをパラメータとして渡すのではない)の形であなたのバリアントを示していただければ、非常にありがたい(そしておそらく私だけではない)。原理的には、2...4は入力パラメータとして渡すことが でき、それは多かれ少なかれ普遍的なものになります(常に同じものが渡されるという意味で、手動で何かを設定する必要はありません)。1をプロシージャーで取得する方法については、まったくアイデアがない。
さらに、すべて同じC++のように、通常、ステートメントは、同じ方法で、マクロに書かれており、私は同じ道を行きました。唯一の弱点は、そのようなマクロを使用するプロシージャ/関数内でxという 入力パラメータまたは変数が宣言されている場合、警告が表示されることです。解決策は簡単で、マクロの中で配列にもっとユニークな名前、例えばassertionFailedArrayを つけることです。
2.違いがわかりません。実行エラーは実行エラーであり、プログラムをクラッシュさせ、それ以上実行されません。しかし、なぜこのような方法をとったかについてお答えします。最初はゼロ除算 だったのですが、このようなマクロをテストしていたところ、なぜかメソッド内で呼び出してもコードの実行が中断されませんでした。OnTickやOnInitなどで呼び出された場合は、そう、実行が止まってしまうのだ。任意のクラスのメソッド内で呼び出された場合は、そうではなかった。MQL5のエラーなのかどうか、私はそれを調べようとはしなかった。)
メソッド内でのゼロによる除算の何が問題なのか、試してみるつもりだ。
#property copyright "Copyright 2015, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property strict //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ struct CFormatOutEol { uchar dummy; }; struct CFormatOutFmtDigits { int digits; }; struct CFormatOutFmtSpace { bool space; }; //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ class CFormatOut { string m_line; string m_dbl_fmt; bool m_auto_space; public: //---- コンストラクタ CFormatOut(int dbl_fmt_digits=4,bool auto_space=false):m_dbl_fmt("%."+(string)dbl_fmt_digits+"f") { } //--- 出力データ CFormatOut *operator<<(double x) { auto_space(); m_line+=StringFormat(m_dbl_fmt,x); return(GetPointer(this)); } CFormatOut *operator<<(string s) { auto_space(); m_line+=s; return(GetPointer(this)); } CFormatOut *operator<<(long l) { auto_space(); m_line+=(string)l; return(GetPointer(this)); } //--- 行末を出力する (実出力/Print関数を呼び出す) CFormatOut *operator<<(CFormatOutEol &eol) { Print(m_line); m_line=NULL; return(GetPointer(this)); } //--- 実数の出力形式を変更する CFormatOut *operator<<(CFormatOutFmtDigits &fmt) { m_dbl_fmt="%."+(string)fmt.digits+"f"; return(GetPointer(this)); } //--- 自動スペース挿入の追加と削除 CFormatOut *operator<<(CFormatOutFmtSpace &fmt) { m_auto_space=fmt.space; return(GetPointer(this)); } protected: void auto_space() { if(m_line!=NULL && m_auto_space) m_line+=" "; } }; CFormatOut OUT; //--- 出力にEndOfLineを挿入するための特別なオブジェクト。 CFormatOutEol EOL; //--- 出力する数字の桁数を設定する CFormatOutFmtDigits DBL_FMT_DIGITS(int digits) { CFormatOutFmtDigits fmt; fmt.digits=digits; return(fmt); } //--- 出力と出力の間にスペースを挿入する/しない CFormatOutFmtSpace AUTO_SPACE(bool enable) { CFormatOutFmtSpace fmt; fmt.space =enable; return(fmt); } //--- 列挙型を文字列に変換する簡単な関数 template<typename T> string EN(T enum_value) { return(EnumToString(enum_value)); }使い方
OUT << AUTO_SPACE(true) << M_PI << "Test" << DBL_FMT_DIGITS(6) << M_PI << EN(PERIOD_M1) << EOL;結果
2015.09.01 18:04:49.060 Test EURUSD,H1: 3.1416 Test 3.141593 PERIOD_M1
注意: OUT << ...という式のパラメータは、右から左へ、逆の順序で指定します。を右から左へ逆順に実行すると、副作用が発生する可能性があります!
もしコード内で出力先(Printでログに出力、アラートに出力、ファイルに出力など)を指定できるのであれば、さらに便利だと思います。特に、それを実行するのは難しいことではありませんから。
P.S.この記事を批判/賞賛してもいいですか?:)
しかし、IMHO!
良いロガーはロギングレベルを持つべきです:
- FATAL - ошибка, дальнейшее выполнение программы невозможно
- ERR - ошибка, выполнение программы можно продолжить
- ATT - предупреждение
- MSG - сообщение
プログラムがデバッグ されているとき、DebugBreakがロガーで呼び出されます- 停止してMQLプログラムの環境(状態)を見ることができます。
プログラムがエンドユーザーで実行されているとき、ロガーメッセージはファイル(print/alert)に保存されます。
デフォルトでは、ロガーはERRとFATALエラーのみを出力し、ユーザーはプログラムを実行しているときに、プログラムのすべてのメッセージ(ATTとMSG)を見るために、常にロギング・レベルを変更することができます。
ログを正しく使用すると、プログラムのエラーを特定/検索するために使用できます。
#property script_show_inputs enum EnLogLevel { __LOG_LEVEL_FATAL, // 致命的なエラーのみ __LOG_LEVEL_ERR, // エラーのみ __LOG_LEVEL_ATT, // 警告とエラー __LOG_LEVEL_MSG, // すべてのメッセージ }; input EnLogLevel LogLevel=__LOG_LEVEL_MSG; // ロガーレベル //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ #define __LOG_OUT(params) ExtTrueLogger.Out params #define __LOG(level,params) do{ if(level<=LogLevel) __LOG_OUT(params); }while(0) #define LOG_MSG(msg) __LOG(__LOG_LEVEL_MSG,(__FUNCSIG__,__FILE__,__LINE__,msg)) #define LOG_ATT(msg) __LOG(__LOG_LEVEL_ATT,(__FUNCSIG__,__FILE__,__LINE__,msg)) #define LOG_ERR(msg) __LOG(__LOG_LEVEL_ERR,(__FUNCSIG__,__FILE__,__LINE__,msg)) #define LOG_FATAL(msg) __LOG(__LOG_LEVEL_FATAL,(__FUNCSIG__,__FILE__,__LINE__,msg)) //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ class CTrueLogger { public: void Out(string func,string file,int line,string msg) { Print(func," ",func," ",file," ",line," ",msg); } } ExtTrueLogger; //+------------------------------------------------------------------+ //| スクリプト番組開始機能| //+------------------------------------------------------------------+ void OnStart() { LOG_MSG("Hello MSG world!"); LOG_ATT("Hello ATT world!"); LOG_ERR("Hello ERR world!"); LOG_FATAL("Hello FATAL world!"); }
この記事ではDEBUG ASSERTについてしか触れていない。 しかし、IMHO! 良いロガーはロギングレベルを持たなければならない:
- FATAL - ошибка, дальнейшее выполнение программы невозможно
- ERR - ошибка, выполнение программы можно продолжить
- ATT - предупреждение
- MSG - сообщение
プログラムがデバッグ されているとき、DebugBreakがロガーで呼び出されます- 停止してMQLプログラムの環境(状態)を見ることができます。
プログラムがエンドユーザーで実行されているとき、ロガー・メッセージはファイル(print/alert)に保存されます。
デフォルトでは、ロガーはERRとFATALエラーのみを生成し、ユーザーはプログラムを実行するときにロギング・レベルを常に変更して、プログラムのすべてのメッセージ(ATTとMSG)を見ることができます。
正しく使用すれば、ログを使用してプログラムのエラーを特定/検索できます。
ちょうど次の記事で(Rashidが承認した場合)ソフトウェアのリリースバージョンですでに「予想される」エラーの処理を計画しており(承認後の論理的な継続として)、これにはログの問題の開示が含まれます。
もし差し支えなければ、この記事に使わせていただきます。
次の記事では(ラシードが承認すれば)、ソフトウェアのリリース・バージョンにおける「予想される」エラーを取り上げようと思っています(承認後の論理的な続きとして)。
もし差し支えなければ、この記事に使わせていただきます。
興味深い話題だ。
この記事を読む少し前に、私は、ブロックの1つにコードループの可能性がある場合に、前提条件によって検出し、プログラムの実行を 即座に中断する方法について自分なりに考えていた。
おっと。
同時に、assert.mqh ファイルをダウンロードし、そこに1行追加した:
#define TEST_TEXT "Line: ",__LINE__,", ",__FUNCTION__,", "
そして、コードではこうなっている:
Print(TEST_TEXT,"a = ",a);
つまり、単純に、コードを構築するときに、コードの作業の終わりまでに、この「作業」情報の出力が簡単に削除できることを期待して、情報の出力を 適用するのである(多くの人が、おそらくコード構築の段階で情報の出力を行い、行っているように)。
興味深い話題だ。
この記事を読む少し前に、私は、ブロックの1つにコードループの可能性がある場合に、前提条件によって検出し、プログラムの実行を 即座に中断する方法について自分なりに考えていた。
おっと。
同時に、assert.mqh ファイルをダウンロードし、そこに1行追加した:
そして、コードではこうなっている:
つまり、単純に、コードを構築するときに、そのコードでの作業の終わりまでに、この「作業中の」情報の出力が簡単に削除できることを期待して、情報の出力を適用するということだ(多くの人が、おそらくコード構築の段階で情報の出力を行い、そうしていると思う)。
フィードバックをありがとう!
TEST_TEXTを条件付きコンパイルで本当に簡単に削除できるようにするには、マクロの中にPrintを 入れることを考えます。現在のバージョンでは、TEST_TEXTを削除するのは簡単ですが、Print自体は削除できないと思います。

- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
新しい記事 MQL5 でのアサーション はパブリッシュされました:
この記事では、MQL5でのアサーションの利用について扱います。アサーションメカニズムとアサーションを実装するための一般的なガイダンスを2つの例として提供します。
ここでは、文字通り「0が1より大きいか確認すること」を意味するアサーションを行います。このアサーションは、明らかに偽で、エラーメッセージが表示されます。:
図1。アサーションの例
作者: Sergey Eremin