このCコードの出力は49ですが、誰かが私にその方法を説明できますか?[複製]
#include <stdio.h>
#define CUBE(x) (x * x * x)
int main() {
printf("%d", CUBE(4+5));
return 0;
}
回答
マクロはコードを次のように変換します。
printf("%d", (4+5 * 4+5 * 4+5));
これは効果的に:
printf("%d", 4 + (5*4) + (5*4) + 5); // 29
9
を取得するためにキューブ化する729
場合は、を記述する必要がありますCUBE((4+5))
。
コンパイルプロセス中にマクロがどのように展開されるかを次に示します。
printf("%d", (4+5 * 4+5 * 4+5));
*
はよりも優先順位が高いため+
、この式はとして評価され(4 + (5 * 4) + (5 * 4) + 5)
、49
期待されるの代わりに生成され729
ます。
このような演算子の優先順位の問題を回避するには、式自体だけでなく、すべてのマクロ引数をマクロ定義で括弧で囲む必要があります。
#define CUBE(x) ((x) * (x) * (x))
ただし、この展開は複数回CUBE
評価されることに注意してくださいx
。これは、マクロ引数にCUBE(i++)
。などの副作用がある場合に問題になります。
これらすべての問題を回避するには、関数を使用してコンパイラーに最適化させます。
int cube(int x) {
return x * x * x;
}
static inline
この関数定義の前に追加できますが、最新のオプティマイザーはこれがなくても関数をインライン化します。
Cプリプロセッサは、文字通りxのすべてのインスタンスを4 + 5に置き換え、次のコードになります。
i = 4+5*4+5*4+5;
(最初に乗算、次に加算)
CUBE((4+5))
番号を追加してからに送信する場合のように、入力を行う必要がありますCUBE
。原因thCUBE(4+5)
は4+5*4+5*4+5
、全体4+5
をx
。の代わりに設定するため、基本的にに拡張されます。したがって、4+5*4+5*4+5
=4+20+20+5
乗算が最初に来て、次にそれらを加算すると、が得られ49
ます。
マクロを#define CUBE(x) ((x)*(x)*(x))
、実際に最初(4+5)
にすべての操作を(x)
実行してから*
操作を実行するように定義します。
もう1つの方法はCUBE((4+5))
、マクロの呼び出し中に使用することです。基本的に、最初に2つの数値と(4+5)
=9
を追加してからCUBE(9)
、次のように実行します。
#include<stdio.h>
#define CUBE(x) (x * x * x)
int main( )
{
printf("%d", CUBE((4+5)));
return 0;
}
Modern Cを読んでから、n1570ドラフトC標準、およびGCCとGDBとCPPのドキュメントを読んでください。このCリファレンスWebサイトも参照してください。
githubやGNUソフトウェアなど、既存のオープンソースプロジェクトからインスピレーションを得てください。
最近のGCCコンパイラでは、として呼び出しgcc -Wall -Wextra -g
ます。-C -E
オプションを使用して、前処理されたフォームを取得します。
また、GCCのstatement-expr拡張機能にも興味があるかもしれません。
あなたCUBE(4+5)
はマクロ展開4+5*4+5*4+5
され4+(5*4)+(5*4)+5
、C演算子の優先順位に従って計算されます。
次のstatic inline
ような関数のコーディングを検討してください
static inline int cube(int x) { return x*x*x; }
または、マクロが必要な場合は、少なくとも
#define CUBE(X) ((X)*(X)*(X))
これはうまく機能CUBE(i++)
しません(inline
関数を使用cube(i++)
している間、あなたがしたいことをします:i
一度インクリメントしてください!)。
ところで、GPPまたはGNU m4(または独自のジェネレーターまたはGNU bison)を使用してCコードを生成することができます。経験則として、ASTで考えてください。Cコードを生成するときは、Chicken Scheme、SWIG、CAIA、または私のmanydl.cのように、多くの役に立たない括弧を出力します。
コード(およびおそらくFrama-C)でClang静的アナライザーを使用することもできます。
MISRACやGNUのようなコーディングガイドラインを読むことに興味があるかもしれません。