關於宏定義的知識,以及一些應用

關於宏定義的知識

define 處理過的數據是無類型的,並且不會開闢內存空間,只是進行了替換

#define pi 10;
s=pi;*r*r

如果給了分號那麼再調用在這種情況時就會出現錯誤。

另外宏定義時一種替換

int max(int a, int b)
{
	return a > b ? a : b;
}
#define MAX(a,b) ( a > b ? a : b)

void main()
{
	int x = 10, y = 20;
	max(++x, y);
	cout << x << endl;//這種結果x=11
	MAX(x, ++y);//,這是應爲在預編譯時進行了一次 ( x > ++y ? x : ++y)這時已經執行了一次++y,然後在編譯運行時再次進行了這樣函數
	cout << y << endl;//y=22;

}

在進行替換後函數會變爲

int max(int a, int b)
{
	return a > b ? a : b;
}
#define MAX(a,b) ( a > b ? a : b)

void main()
{
	int x = 10, y = 20;
	max(++x, y);//這種結果x=11
	cout << x << endl;
	 ( x > ++y ? x : ++y);
	cout << y << endl;

}

再舉一個例子

#define NUM(a,b) a*b
void main()
{
	int x = 3, y = 4;
	cout << NUM(x + 5, y + 6);
}

在我的想法中原本以爲替換後會變爲

cout<<(x+5)*(y+6);

但是實際情況卻是cout << x + 5*y + 6;如果想要得到我之前所設想的結果需要把宏定義改爲#define NUM(a,b) (a)*(b)這是應爲a和b是一個整體所以替換後a變爲
x+5,但是這是沒有小括號的。

const int PI =12;
全局變量實在編譯時確定的,常變量進行類型檢查,並且開闢空間
enum{ok=0,error=1};//無名枚舉類型
枚舉類型也不會再預編譯時被替代

#pragma once是一個比較常用的C/C++雜注,只要在頭文件的最開始加入這條雜注,就能夠保證頭文件只被編譯一次。
#ifndef的方式依賴於宏名字不能衝突,這不光可以保證同一個文件不會被包含多次,也能保證內容完全相同的兩個文件不會被不小心同時包含。當然,缺點就是如果不同頭文件的宏名不小心"撞車",可能就會導致頭文件明明存在,編譯器卻硬說找不到聲明的狀況#pragma once則由編譯器提供保證:同一個文件不會被包含多次。注意這裏所說的"同一個文件"是指物理上的一個文件,而不是指內容相同的兩個文件。帶來的好處 是,你不必再費勁想個宏名了,當然也就不會出現宏名碰撞引發的奇怪問題。對應的缺點就是如果某個頭文件有多份拷貝,本方法不能保證他們不被重複包含。當 然,相比宏名碰撞引發的"找不到聲明"的問題,重複包含更容易被發現並修正
從這引用https://www.cnblogs.com/terrytian88/p/5820159.html

#include的本質是拷貝文件,將文件的所有內容拷貝到源文件中,在預編譯中完成,會將資源文件中的ascii值轉換爲相應的值(通過atoi函數)。
在這裏插入圖片描述在這裏插入圖片描述
這是相應的用法
使用尖括號的話,編譯時會先在系統include目錄裏搜索,如果找不到纔會在源代碼所在目錄搜索;使用雙引號則相反,會先在源代碼目錄裏搜索。這就意味着,當系統裏(如/usr/include/裏)有一個叫做math.h的頭文件,而你的源代碼目錄裏也有一個你自己寫的math.h頭文件,那麼使用尖括號時用的就是系統裏的;而使用雙引號的話則會使用你自己寫的那個。
2、使用尖括號的話,編譯時會先在系統include目錄裏搜索,如果找不到纔會在源代碼所在目錄搜索。
3、使用雙引號則相反,會先在源代碼目錄裏搜索,如果未找到則去系統默認目錄查找,通常用於包含程序作者編寫的頭文件。

寫一個my_memcpy

struct node
{
	int a;
	char b;
};
#defne DEBUG//這是已定義狀態,會進行if判空
enum status {point1error,point2error};
void *my_memcpy(const void *p1, void *p2,  unsigned int n)//參數表的類型應該爲無類型,n表示字節數這樣即使在調用結構體或者數組是依舊可以使用,另外之所以在P1前加const是爲了避免當複製對象是常量時,指針只能爲常指針才能成功調用
{                                                         //另外之所以返回時是一個泛型指針,爲的是個strcpy一樣可以多次複製更加方便
#ifdef DEBUG
	if ((p1 == NULL) || (p2 == NULL))  //判空是十分重要的
	{
		return NULL;
	}
#endif
	char *p3 = (char*)p1;//之所以強轉是爲了達到每一個字節都複製的效果
	char *p4 = (char*)p2;//這裏就是爲了實現鏈式表達的作用從而達到多是使用
	while (n--)
	{
		*p4++ = *p3++;
	}
	return p2;
}
void main()
{
	node a = { 3, 'm' };
	node b;
	node c;
	my_memcpy(&a, &b, sizeof(node));
	my_memcpy(my_memcpy(&a, &b, sizeof(node)), &c, sizeof(node));
}


//上面的#define DEBUG
#ifdef DEBUG
#endif 
這是另一種宏定義的方式,當我們給DEBUG進行#define的宏定義時那麼程序中的判斷指針是否爲NULL就會起作用,若不進行定義則在編譯的過程中會把判空函數給自動取消編譯。
也可以這麼操作
#ifdef  YHP(宏名)                     #ifndef  YHP(和前面的功能相反)後面是未定義宏名就進行之下內容
。。。                                  。。。
。。。                                  。。。
#else                                   #else
。。。                                  。。。
。。。
#endif                                  #endif  


還有一種做法
#if 0                          #if 1      //這兩種情況和上面的#ifdef不同在使用這種方式是宏名要有宏值  1或0,而上面的那種的執行和宏值無關
.。。                          。。。
#else                          #else
。。                           。。。
#endif                         #endif

除了這種手寫的通過宏定義的方式來確定是否判空之外還可以使用系統自帶的函數assert

#include<assert.h>
assert(p1!=NULL||p2!=NULL);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章