詳細な前処理(2つ)-#defineはマクロと識別子を定義します+マクロと関数の比較+#と##の役割

#definedefine識別子

#definedefine識別子の形式は次のとおりです。

#define MAX 100
#define reg register//懒人觉得register太长了

#defineで定義されたこれらの識別子は、前処理段階で対応するコンテンツを持つコンパイラによって置き換えられます。以前はもっと興味深いものを見たので、ここで共有します。

#define mian main
#define , ,
#define ( (
#define ) )
#define ture true
#define ; ;

実際、ファイルの前にこれらの単語を追加する限り、コードに中国語で句読点を書くことを心配する必要はありません。また、mainをmianとして、trueをtureとして書くことを心配する必要もありません。間違えても正しいものに交換しております。ただし、これらの低レベルのエラーを回避するために、コードを作成するときは注意が必要です。

#definedefineマクロ

#defineメカニズムには、パラメーターをテキストに置き換えることができるプロビジョニングが含まれています。この実装は通常、マクロまたは定義マクロと呼ばれます。

たとえば、マクロを使用して、数値の2乗を実現します。

#include <stdio.h>
#define SQUARE(x) x*x//求x的平方
int main()
{
    
    
	int ret = SQUARE(5);
	//相当于int ret = 5*5;
	printf("%d\n", ret);//结果为25
	return 0;
}

ただし、渡すマクロパラメータが2 + 3の場合、出力される結果は25ではなく11であるため、これは完全には正しくありません。マクロは置換を完了するため、最初に2 + 3の値を計算してから置換するのではなく、直接置換します。したがって、2 +3を渡すことは次のようになります。

	int ret = 2+3*2+3;

*は+よりも優先度が高いため、この計算の結果はもちろん11になります。この状況を回避するには、マクロを使用して数値の2乗を達成する必要があります。

#define SQUARE(x) ((x)*(x))

(x)*(x)を括弧で囲む理由は同じですが、マクロを使用するときの演算子の優先順位によって引き起こされる予測できない結果を回避するためです。

したがって、#defineを使用してマクロを定義するときは、かっこを気にせず、必要な場所に追加してください

#define置換ルール

プログラム内での#defineで定義されたマクロと識別子を交換する場合、いくつかのステップがあり、関係
レッツ・使用例として、次のコード:

#include <stdio.h>
#define MAX 100
#define SQUARE(x) ((x)*(x)*MAX)
int main()
{
    
    
	int ret = SQUARE(5);
	printf("%d\n", ret);
	return 0;
}

1.マクロを呼び出すときは、最初にパラメーターをチェックして、#defineで定義されたシンボルが含まれているかどうかを確認します。そうである場合は、最初に交換されます。
たとえば、#defineで定義されたマクロに#defineで定義されたシンボルMAXが含まれている場合、このマクロを呼び出すときは、最初にMAXを置き換えます。

#include <stdio.h>
#define SQUARE(x) ((x)*(x)*100)
int main()
{
    
    
	int ret = SQUARE(5);
	printf("%d\n", ret);
	return 0;
}

2.次に、置換テキストがプログラムの元のテキスト位置に挿入されます。マクロの場合、パラメーター名はそれらの値に置き換えられます。
たとえば、上記の例のこの手順の後、コードは次のようになります。

#include <stdio.h>
int main()
{
    
    
	int ret = ((5)*(5)*100);
	printf("%d\n", ret);
	return 0;
}

3.最後に、結果ファイルを再度スキャンして、#defineで定義されたシンボルが含まれているかどうかを確認します。そうである場合は、上記のプロセスを繰り返します。
上記の例には、#defineで定義されたシンボルは含まれていません。

注:
1。他の#defineで定義された変数は、マクロパラメーターと#define定義に表示される場合があります。ただし、マクロの場合、再帰は発生しません。
つまり、次のようなコードは表示されません。

#define FAC(x) (x)*FAC(x-1)//error

2.プリプロセッサが#defineで定義されたシンボルを検索する場合、文字列定数の内容は検索されません。
たとえば、次のコード文字列のMAXは100に置き換えられませんが、文字列の外側のMAXは置き換えられます。

#include <stdio.h>
#define MAX 100
int main()
{
    
    
	printf("MAX = %d\n", MAX);//结果为MAX = 100
	return 0;
}

副作用のあるマクロパラメータ

副作用のあるマクロパラメータ紹介する前に、副作用あるとはどういう意味かを見てみましょう

	int a = 10;
	int b = a + 1;//无副作用
	int c = a++;//有副作用

コードでは、bとcの両方がa + 1の値を取得する必要がありますが、aの値は変更しません。bがa + 1の値を取得した後、aの値は変化しないため、副作用はありませんが、cがa + 1の値を取得した後、aの値も変化します。つまり、副作用があります。 。簡単に言えば、コードの実行後、目的の結果が得られるだけでなく、他の問題も発生します。このステートメントには副作用があると言えます。

マクロパラメータがマクロの定義に複数回出現する場合、そのパラメータに副作用があると、このマクロを使用するときに危険が生じ、予期しない結果が生じる可能性があります。副作用は、式が評価されるときに発生する永続的な効果です。
たとえば、aとbのサイズを比較し、大きい方の値をcに割り当ててから、aとbの両方に1を追加します。

#include <stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
    
    
	int a = 10;
	int b = 20;
	int c = MAX(a++, b++);
	printf("%d\n", c);
	return 0;
}

このコードは問題ないようですが、マクロを置き換えた後は次のコードと同等であるため、結果は正しくありません。

#include <stdio.h>
int main()
{
    
    
	int a = 10;
	int b = 20;
	int c = ((a++)>(b++)?(a++):(b++));
	printf("%d\n", c);
	return 0;
}

置換後、分析するとすぐに答えを得ることができます.cの最終結果は21であり、コードが実行された後、aとbの値が同時に1増加することはありません、 aの値が11に変更され、bの値が変更されました。22の場合。

したがって、マクロを使用する場合は、副作用のあるマクロパラメータを渡さないようにする必要があります

マクロと関数の比較

マクロは通常、簡単な操作を実行するために使用されますたとえば、2つの数値のうち大きい方を見つけます。

#define MAX(x,y) ((x)>(y)?(x):(y))

では、次の機能を使ってこの機能を実現してみませんか?

int Max(int x, int y)
{
    
    
	return x > y ? x : y;
}

1.関数を呼び出して関数から戻るために使用されるコードは、この小さな計算作業の実際の実行よりも時間がかかる場合があります。したがって、マクロは、プログラムのサイズと速度の点で関数よりも優れています。

2.さらに重要なことに、関数のパラメーターは特定のタイプとして宣言する必要があります。したがって、関数は適切なタイプの式でのみ使用できます。ただし、マクロは、整数、長整数、浮動小数点型などと比較できる型に適用できます。マクロはタイプに依存しません。

さらに、マクロは関数が実行できないことを実行できる場合があります。たとえば、マクロパラメータには型を含めることができますが、関数にはできません
malloc関数を使用してメモリ空間を開くと、コードが多すぎると感じる場合があります。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
	int* p1 = (int*)malloc(10 * sizeof(int));
	if (p1 == NULL)
	{
    
    
		printf("p1开辟失败\n");
		return 1;
	}
	free(p1);
	p1 = NULL;
	return 0;
}

現時点では、mallocでスペースを開くときに、開いた型とその型の要素の数だけを渡す必要があるように、マクロを実装できます。

#include <stdio.h>
#include <stdlib.h>
#define MALLOC(num,type) (type*)malloc(num*sizeof(type))
int main()
{
    
    
	int* p2 = MALLOC(10, int);
	if (p2 == NULL)
	{
    
    
		printf("p2开辟失败\n");
		return 1;
	}
	free(p2);
	p2 = NULL;
	return 0;
}

ただし、マクロには次のような欠点もあります。

  1. マクロが使用されるたびに、マクロ定義コードのコピーがプログラムに挿入されます。マクロが比較的短い場合を除いて、プログラムの長さが大幅に長くなる可能性があります。
  2. マクロはデバッグできません。
  3. マクロは型に依存しないため、厳密ではありません。
  4. マクロは、演算子の優先順位に問題を引き起こし、プロセスでエラーが発生しやすくなる可能性があります。

以下に、マクロと関数の違いをより明確に区別できるフレームワーク図を示します。
ここに画像の説明を挿入

人気のない知識ポイント:#と##

ここで言及されている#と##の使用は非常にまれであり、一部のブロガーはそれを聞いたことがないかもしれませんが、この知識ポイントはインタビュー中にテストされることもあります。これもより重要です。
1.
ここで言及されている#の関数は、#defineおよび#includeの#ではありません。ここで言及されている#の関数は、マクロパラメータを対応する文字列に変換することです。

それで、この#の実際の機能は何ですか?
#の機能を紹介する前に、説明させてください。文字列には自動接続の特徴があります
たとえば、次の場合です。

	char arr[] = "hello ""world!";
	//等价于char arr[] = "hello world!";
	printf("helll ""world!\n");
	//等价于printf("helll world!\n");

次に、#のユースケースを紹介します。たとえば、次のコードがあります。

#include <stdio.h>
int main()
{
    
    
	int age = 10;
	printf("The value of age is %d\n", age);
	double pi = 3.14;
	printf("The value of pi is %f\n", pi);
	int* p = &age;
	printf("The value of p is %p\n", p);
	return 0;
}

printfで出力されるコンテンツのほとんどが同じであることがわかりました。コードの冗長性を回避するために、関数またはマクロにカプセル化できますか?
考えて実験した結果、関数も通常のマクロもこの機能を実現できないことがわかりましたそれがテストに行くことができると信じていないブロガー。
このとき、この#を使用する必要があります。コードは次のとおりです。

#include <stdio.h>
#define print(data,format) printf("The value of "#data" is "format"\n",data)
int main()
{
    
    
	int age = 10;
	print(age, "%d");
	double pi = 3.14;
	print(pi, "%f");
	int* p = &age;
	print(p, "%p");
	return 0;
}

現時点では、印刷する変数の変数名と印刷形式を渡すだけで済みます。このコードは、前処理後の次のコードと同等です。

#include <stdio.h>
int main()
{
    
    
	int age = 10;
	printf("The value of ""age"" is ""%d""\n", age);
	double pi = 3.14;
	printf("The value of ""pi"" is ""%f""\n", pi);
	int* p = &age;
	printf("The value of ""p"" is ""%p""\n", p);
	return 0;
}

また、文字列が自動的に接続されるため、目的の結果を印刷できます。
2。##は、その両側のシンボルを1つのシンボルに組み合わせる
ことができます。これにより、マクロ定義で個別のテキストフラグメントから識別子を作成できます

たとえば、以下で定義されているマクロは、2つの着信シンボルを1つのシンボルに結合できます。

#include <stdio.h>
#define CAT(x,y) x##y
int main()
{
    
    
	int workhard = 100;
	printf("%d\n", CAT(work, hard));//打印100
	return 0;
}

おすすめ

転載: blog.csdn.net/chenlong_cxy/article/details/115267432