次の式でマクロを作成しようとしています:(a^2/(a+b))*b
、そして私はゼロによる除算がないことを確認したいと思います。
#define SUM_A( x, y ) if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
次に、main内でマクロを呼び出します。
float a = 40, b = 10, result;
result = SUM_A(a, b);
printf("%f", result);
If関数の前後に角かっこを使用してみましたが、ifステートメントの前に構文エラーが発生し続けます。また、returnを使用してみましたが、defineでそれを使用することは想定されていません。
#define
はプリプロセッサによって解釈され、出力は次のようになるため、ifステートメントは使用できません。
result=if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
これは間違った構文です。
ただし、代わりに三項演算子を使用することもできます。定義を次のように変更します
#define SUM_A( x, y ) ((x) == 0 || (y) == 0 ? 0 : ( ( ( (x) * (x) ) / ( ( x ) + ( y ) ) ) * ( y ) ))
置換するときの構文エラーを回避するために、常に括弧内に定義を置くことを忘れないでください。
if
は、式ではなくステートメントを導入します。 「3項」(条件付き)演算子を使用します。
#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))
または、これをinline
関数にします。
inline float sum_a(float x, float y)
{
if (x == 0 || y == 0)
return 0;
else
return ((x * x) / (x + y)) * y;
}
これにより、x
やy
の複数の評価の問題が回避され、読みやすくなりますが、x
とy
のタイプは修正されます。 inline
を削除して、この関数をインライン化する価値があるかどうかをコンパイラーに判断させることもできます(inline
は、インライン化を実行することを保証するものではありません)。
#define
でif
ステートメントを使用することは技術的に可能です(ただし、期待した方法ではありません)。 #define
sは、基本的には空想的なテキストの検索と置換なので、それらがどのように展開されるかについては十分に注意する必要があります。これが機能することがわかりました...
#define SUM_A(x, y) \
({ \
float answer; \
if ((x) == 0 || (y) == 0) { \
answer = 0; \
} else { \
answer = ((float)((x)*(x)) / ((x)+(y))) * (y); \
} \
(answer); \
})
// Typecasting to float necessary, since int/int == int in C
このマクロの内容の簡単な説明:
\
は、行の継続を通知するためのものです(つまり、「このマクロは次の行に続く」とコンパイラに伝えます)x
が2+1
の場合、(x)*(x)
は(2+1)*(2+1)
に展開され、9(希望どおり)になりますが、x*x
は2+1*2+1
に展開され、5(希望どおりではありません)になります。return
値のように機能します(したがって、最後に(answer);
があります)これはあなたが探している結果を与えるはずであり、複数のelse if
を含めるように拡張できない理由はありません(他の回答が指摘しているように、可能であれば三項演算子を使用する方が簡単です)。
マクロには複数の問題があります:
ステートメントに展開されるため、式として使用できません
引数が展開で適切に括弧で囲まれていません。このマクロを変数名または定数以外で呼び出すと問題が発生します。
引数は複数回評価されます。SUM_A(a(), b())
やSUM_A(*p++, 2)
などの副作用のある引数を使用してマクロを呼び出すと、副作用が複数回発生します。
これらすべての問題を回避するには、static inline
として定義されている可能性がある関数を使用して、コンパイラーがさらに最適化できるようにします(これはオプションであり、最新のコンパイラーはこれを自動的に行います)。
static inline int SUM_A(float x, float y) {
if (x == 0 || y == 0)
return 0;
else
return x * x / (x + y) * y;
}
ノート:
問題は、if
ステートメントが式ではなく、値を返さないことです。さらに、この場合にマクロを使用する十分な理由はありません。実際、これは非常に深刻なパフォーマンスの問題を引き起こす可能性があります(マクロ引数として渡すものによって異なります)。代わりに関数を使用する必要があります。
私は条件付きのマクロをかなり使用していますが、それらには合法的な使用法があります。
基本的にブロブであるいくつかの構造があり、すべてが単なるuint8_tストリームです。
内部構造をより読みやすくするために、条件付きマクロがあります。
例...
#define MAX_NODES 10
#define _CVAL16(x)(((x) <= 127) ? (x) : ((((x) & 127) | 0x80) ), ((x) >> 7)) // 1 or 2 bytes emitted <= 127 = 1 otherwise 2
次に、配列内でマクロを使用します...
uint8_t arr_cvals[] = { _CVAL16(MAX_NODES), _CVAL16(345) };
配列では3バイトが放出され、最初のマクロは1バイトを放出し、2番目のマクロは2バイトを放出します。これはコンパイル時に評価され、コードを読みやすくします。
私も...例えば...
#define _VAL16(x) ((x) & 255), (((x) >> 8) & 255)
元の問題については、おそらく定数を使用して結果を使用したいと思うかもしれませんが、もう一度、実際にそれがどこでどのように使用されるのかということに行き着きます。
#define SUM_A(x, y) (!(x) || !(y)) ? 0 : ((x) * (x) / ((x) + (y)) * (y))
float arr_f[] = { SUM_A(0.5f, 0.55f), SUM_A(0.0f, -1.0f), SUM_A(1.0f, 0.0f) };
実行時に持つことができます...
float x;
float y;
float res = SUM_A(x,y); // note ; on the end
Cプログラム内のコードとして含まれているフォントを作成するプログラムがあります。ほとんどの値は、32ビット値を4バイトに、4バイトに浮動するなどのマクロにラップされています。
はい、マクロ内にifステートメントを含めることができます。正しくフォーマットする必要があります。次に例を示します。
#define MY_FUNCTION( x ) if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); }