組み込み C 言語マクロのネストの展開ルール

編集元: https://mp.weixin.qq.com/s/xos8z1tpptLpAV6kQFXpuQ

組み込み C 言語では、マクロはプリコンパイル中に、コード内のマクロ名がマクロ本体の内容で「テキスト置換」されます。

1. 一般的な展開規則は関数のパラメータと同じです。最初にパラメータを展開し、次に関数を分析します。つまり、内側から外側に展開します。2. マクロ内に # 演算子がある場合、パラメータは展開されません。3. マクロ内に ## 演算子がある場合は、関数を展開してからパラメータを分析します。4. ## 演算子は、パラメータを結合するために使用されます。前処理プロセスでは、## 演算子の両側にあるパラメータが 1 つの記号に結合されます。これは文字列ではないことに注意してください。

2.「#」「##」の使用規則

「#」はマクロパラメータを文字列に変換します。パラメータマクロが何であっても、つまり「本来の姿」が文字列で表示されます。つまり、マクロ パラメーターを二重引用符 "" で囲んで文字列を形成します。例えば:

#define T(x) #x
int temp = 10;
cout<<T(temp)<<endl;//输出 temp 而不是 10
// T(temp) -> "temp" (将宏参数用双引号包含起来形成一个字符串)

「##」は連結と呼ばれ、マクロパラメータと前のトークン(パラメータ/文字列スペースなど)を接続します。例えば:

#define T(x) x##[2]
int a[5] = {1,2,3,4,5};
cout<<T(a)<<endl; //输出 3 即 a[2]
// 1. 宏参数在宏体中未加括号包裹起来
#define T(a) a*10
int a = 1;
cout<<T(a+1)<<endl; //输出 11 而非20

// 2. 整个宏体内容未加括号包裹起来
#define T(x) x+1
cout<<10*T(1)<<endl; //输出 11 而非20

1. マクロ定義では、パラメータに括弧を追加します。これにより、置換時に括弧内の式が最初に演算されることが保証されます。2. 括弧を使用してマクロ定義全体の内容を囲み、マクロ定義全体の式が最初に操作されるようにします。マクロのネストはマクロを使用する上で難しい点であり、間違いが発生しやすい点でもあります。マクロのネストの展開ルールをフローチャートで説明します。

写真

マクロのネストされた展開ルールのフローチャート

注: 上図の 2 と 3 は条件であり、どちらかの条件が満たされていれば処理 5 に入ります。次の例は次のことを示しています。

// example 1
#include <cstdio>#define TO_STRING2(x) #x
#define TO_STRING1(x) #x
#define TO_STRING(x) TO_STRING1(x)

#define PARAM(x) #x
#define ADDPARAM(x) INT_##x
 
int main()
{
  const char *str = TO_STRING(PARAM(ADDPARAM(1)));
  printf("%s\n",str); //输出: "ADDPARAM(1)"
 
  str = TO_STRING2(PARAM(ADDPARAM(1)));
  printf("%s\n",str); //输出: PARAM(ADDPARAM(1))
 
  return 0;
}

上の例の 2 つのネストされたマクロの展開プロセスは次のとおりです。

TO_STRING(PARAM(ADDPARAM(1)))

-> 展开 PARAM:TO_STRING("ADDPARAM(1)")

-> 展开 TO_STRING:TO_STRING1("ADDPARAM(1)")

-> 展开 TO_STRING1:"\"ADDPARAM(1)\""

TO_STRING2(PARAM(ADDPARAM(1)))

-> 展开 TO_STRING2:"PARAM(ADDPARAM(1))"
// example 2
#include <cstdio>#define TO_STRING2(x) a_##x
#define TO_STRING1(x) #x
#define TO_STRING(x) TO_STRING1(x)

#define PARAM(x) #x
#define ADDPARAM(x) INT_##x
 
int main()
{
  const char *str = TO_STRING(TO_STRING2(PARAM(ADDPARAM(1))));
  printf("%s\n",str); //输出: a_PARAM(INT_1)
  return 0;
}

上記の例のネストされたマクロの展開プロセスは次のとおりです。

TO_STRING(TO_STRING2(PARAM(ADDPARAM(1))))

-> 展开 TO_STRING2:TO_STRING(a_PARAM(ADDPARAM(1))) //注意此次展开后,PARAM宏名被破坏了,变成了a_PARAM不再是有效的宏名了

-> 展开 ADDPARAM:TO_STRING(a_PARAM(INT_1))

-> 展开 TO_STRING:TO_STRING1(a_PARAM(INT_1))

-> 展开 TO_STRING1:"a_PARAM(INT_1)"

注: ネストされたマクロの展開規則はコンパイラに関連しており、異なるコンパイラでは同じネストされたマクロを異なる方法で展開する場合があります。上記のテストはすべて VS2010 (x86) 上で行われます。

原文:https://zhuanlan.zhihu.com/p/344240420文章来源于网络,版权归原作者所有,如有侵权,请联系删除。

个人微信开放,扫码添加,进高质量嵌入式交流群

关注我【一起学嵌入式】,一起学习,一起成长。
觉得文章不错,点击“分享”、“赞”、“在看” 呗!

おすすめ

転載: blog.csdn.net/qq_41854911/article/details/131525355