このCコードの出力は49ですが、誰かが私にその方法を説明できますか?[複製]

Jan 20 2021
#include <stdio.h>

#define CUBE(x) (x * x * x)

int main() {
    printf("%d", CUBE(4+5));
    return 0;
}

回答

5 MarkSouls Jan 20 2021 at 14:31

マクロはコードを次のように変換します。

printf("%d", (4+5 * 4+5 * 4+5));

これは効果的に:

printf("%d", 4 + (5*4) + (5*4) + 5); // 29

9を取得するためにキューブ化する729場合は、を記述する必要がありますCUBE((4+5))

9 chqrlie Jan 20 2021 at 14:34

コンパイルプロセス中にマクロがどのように展開されるかを次に示します。

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この関数定義の前に追加できますが、最新のオプティマイザーはこれがなくても関数をインライン化します。

3 Tecto Jan 20 2021 at 14:32

Cプリプロセッサは、文字通りxのすべてのインスタンスを4 + 5に置き換え、次のコードになります。

i = 4+5*4+5*4+5;

(最初に乗算、次に加算)

3 SahadatHossain Jan 20 2021 at 14:31

CUBE((4+5))番号を追加してからに送信する場合のように、入力を行う必要がありますCUBE。原因thCUBE(4+5)4+5*4+5*4+5、全体4+5x。の代わりに設定するため、基本的にに拡張されます。したがって、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;
}
1 BasileStarynkevitch Jan 20 2021 at 14:29

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のようなコーディングガイドラインを読むことに興味があるかもしれません。