FreeBASIC マニュアルのトップに戻る

FreeBASIC ProPgMacros

目次→教本→プログラマーのための案内Macros←オリジナル・サイト

マクロ 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

Macros は、名前付きのコードセグメントで、プログラム内で検出されるたびに、その名前に置き換えられます。

マクロは、言語を拡張し、再利用可能なコードを作成する、強力な方法を提供します。
マクロが使われる理由の1つは、パフォーマンスです。
これらは常にインラインで展開されるため、手続き呼び出しのオーバーヘッドを排除する方法です。
FreeBASIC では、インライン手続きをサポートしていないため、マクロに代わるものはありません。

マクロ定義
プリプロセッサは、文字列置換メカニズムの中に、置換される識別子に、提供されたパラメータを使えます。
これらのパラメーターは、置換文字列で、変更せずに置換されます。
置換文字列は、マクロと呼ばれます。

マクロを定義する構文は次のとおりです('Preprocessor commands' を参照):
- one-line macro:
#define identifier([parameters]) body
parameters は、定義を関数のようなマクロに変換し、文字列引数をマクロに渡すことができます。
identifier の直後に開き括弧(()を挿入し、その間に空白を入れないでください。そうしないと、コンパイラーはそれを bodyの一部として扱います。
- multi-line macro:
#macro identifier([parameters])
body
#endmacro
#macro は、#define の複数行バージョンです。

# stringize 演算子を、マクロ・パラメーターで使って、マクロ・パラメーターを文字列リテラルに変換できます。また、## concatenate 演算子を使って、トークンをマージできます。
('Preprocessor Operators' を参照)

定義とマクロは、 scope されます(これらは、定義されたスコープでのみ、表示されます)。
一方、名前空間は、定義とマクロの可視性に、影響を与えません。

マクロのメカニズムにより、すべての型で機能する、一般的な手続きと同等のことができます。
ただし、マクロに渡されるパラメーターは、マクロ定義で使用されるたびに、マクロによって評価されることに、注意する必要があります。
これにより、パフォーマンスの問題が発生したり、さらに悪いことに、望ましくないエッジ効果(境界部分が外部からの影響を受けること)が発生する可能性があります。

括弧は、常にマクロのパラメーターを囲む必要があります:
- 実際、これらのパラメーターは複合式にすることができ、マクロで使う前に、完全に計算する必要があります。
- 括弧は、この計算を強制します。
- 設定されていないと、優先度ルールは、マクロ自体で、論理エラーを生成する可能性があります。
同様に、値を返すマクロは、別の式で使う前に、完全な評価を強制するために、括弧で囲む必要があります。

正しくないマクロと、正しいマクロの例:

#define MUL1(x, y) x * y              '' incorect macro  (parameters must be enclosed in parentheses)
#define MUL2(x, y) ( x ) * ( y )      '' incorrect macro (and returned result must also be in parentheses)
#define MUL3(x, y) ( ( x ) * ( y ) )  '' correct macro

Print MUL1(5-3, 1+2)^2  '' 6  (incorrect result)
Print MUL2(5-3, 1+2)^2  '' 18 (incorrect result)
Print MUL3(5-3, 1+2)^2  '' 36 (correct result)

Sleep

したがって、括弧は、マクロの一貫した動作を保証します(括弧は、マクロ定義に追加しますが、絶対に必要です)。

マクロのデバッグ
マクロを使うことは、極めて安全ではなく、見つけるのが非常に難しい、多くの落とし穴を隠します。
手続きは、型チェックとスコープを提供しますが、マクロは、渡された引数を、置き換えるだけです。
マクロのもう 1つの欠点は、プログラムのサイズです。
その理由は、プリ-プロセッサは、プログラムのコンパイル・プロセスの前に、プログラム内のすべてのマクロを、実際の定義に、置き換えるからです。

ソース・コード・ファイルだけを見て、問題の原因を見つける唯一の方法は、マクロの定義を見て、何が起こったかを理解することです。
マクロを使う場合の最も一般的なエラーは、不均衡な開き括弧です(コンパイル時に、エラーが発生します)。
もう1つは、マクロ定義で、引数(または、存在する場合は戻り値)を括弧で囲むことを忘れることです。
これは、演算子の優先順位のために、かなり厄介な副作用を引き起こす可能性があります(コンパイル時のエラーや実行時のバグを引き起こします)。

コンパイラーは(展開後に)マクロ内でエラーを検出すると、素朴なエラー・メッセージを提示します。含まれるのは次のものだけです:
- マクロの呼び出しの行番号、
- エラーの種類、
- (マクロの)呼び出しの文字列。

エラーが明らかでない場合(不鮮明な報告エラーの場合)、唯一の解決策(コール行番号のみ)は、現在、修正が成功するまで、次の 5つのステップを繰り返し実行することです:
Do
1. ソース・ファイルで fbc を呼び出しますが、'-pp' コンパイル・オプションを使います(fbc コマンドは、コンパイルせずに、前処理済みの入力ファイルのみを出力します)。
2. 前処理されたファイルを復元します。
3. この前処理されたファイルから、直接編集およびコンパイルします。
4. エラーを分析し、理解し、修正し、修正された前処理済みファイルを再度コンパイルします。
5. 元のソース・ファイルの、関連するマクロ本文で、同等の修正を後回しにします。
Loop

短いコードのエラーの例:
注: もう1つの解決策は、マクロの呼び出しに関連する、コンパイラからのより詳細なエラーメッセージです(機能リクエストに既に登録されている、改善されたエラーメッセージの提案)。

可変長のマクロ
#macro#define 宣言の最後のパラメータの後ろに省略記号 "..." (3つの点)を使うと、可変長のマクロを作成できます:
#macro identifier([parameters,] variadic_parameter...)
body
#endmacro
or:
#define identifier([parameters,] variadic_parameter...) body

そのため、variadic_parameter を通じて任意の数の引数を渡すことができ、それらは通常のマクロ・パラメータであるかのように本体で使うことができます。
マクロ展開時には、マクロの置換リストにある variadic_parameter の各出現箇所が、渡された引数で置き換えられます。
variadic_parameter は、カンマを含む渡された引数の完全なリストに展開され、完全に空にすることもできます。

可変引数リスト内の個々の引数に、再帰的にアクセスするための直接的な手段は提供されていません。
variadic_parameter によって渡されるさまざまな引数を区別するには、最初に # stringize 演算子を使って variadic_parameter を文字列リテラルに変換し、次にこの文字列リテラル (#variadic_parameter) で渡された各引数を区切り文字 (コンマ) で区別します。


1行と、複数行のマクロの例:

#define MIN(x, y) IIf( ( x ) < ( y ), x, y )      '' maximum function-like macro
#define MAX(x, y) IIf( ( x ) > ( y ), x, y )      '' minimum function-like macro
#define MUL(x, y) ( ( x ) * ( y ) )               '' multiply function-like macro

#macro REV_STR(str_dest, str_src)                 '' reverse-string sub-like macro
    For i As Integer = Len(str_src) To 1 Step -1
        str_dest &= Mid(str_src, i, 1)
    Next I
#endmacro

Print MIN(5 - 3, 1 + 2)    '' 2
Print MAX(5 - 3, 1 + 2)    '' 3
Print MUL(5 - 3, 1 + 2)^2  '' 36

Dim As String s
REV_STR(s, "CISABeerF")  '' FreeBASIC
Print s

Sleep

可変長のマクロを使った例:
' 複数のサブパラメータを含むことができる可変パラメータを持つマクロ:
'   variadic_parameter で渡される異なる引数を区別するため、
'   演算子 # (プリプロセッサ Stringize)を使って、まず variadic_parameter を文字列に変換します。
'   そして、この文字列(#variadic_parameter)の中で、渡された各引数をセパレータ(通常はコンマ)の位置で区別します。

#macro average(result, arg...)
    Scope
        Dim As String s = #arg
        If s <> "" Then
            result = 0
            Dim As Integer n
            Do
                Dim As Integer k = InStr(1, s, ",")
                If k = 0 Then
                    result += Val(s)
                    result /= n + 1
                    Exit Do
                End If
                result += Val(Left(s, k - 1))
                n += 1
                s = Mid(s, k + 1)
            Loop
        End If
    End Scope
#endmacro

Dim As Double result
average(result, 1, 2, 3, 4, 5, 6)
Print result

' Output : 3.5


参照
プログラマーのための案内に戻る
←リンク元に戻る プログラム開発関連に戻る
ページ歴史:2022-09-02 04:28:05
日本語翻訳:WATANABE Makoto、原文著作者:fxm

ホームページのトップに戻る

表示-非営利-継承