test.c(源文件) --> 編譯器 --> test.obj(目標文件,在debug里)
鏈接庫和多個目標文件 經過 鏈接器的處理,最終生成可執行程序.exe
編譯階段
預處理/預編譯階段 :1.頭文件的包含 2.define定義符號的替換,并刪除定義的符號 3.刪除注釋 這三個都是文本操作
編譯:把C語言代碼轉換成匯編代碼
匯編:把匯編代碼轉換成二進制指令,形成符號表
鏈接階段
合并段表
符號表的合并和重定位
預處理
__ FILE__進行編譯源文件的位置
__ LINE__文件當前的行號
__ DATE__文件被編譯的日期
__ TIME__文件被編譯的時間
__ STDC__判斷編譯器是否服從標準C(ANSI C)數值就是1,否則就是沒有定義這個內置符號
可以看出vs不遵循此標準
大多數oj網站使用gcc或者clang編譯器
define定義標識符
后面加上“;”是一種非常坑爹的行為
#define MAX 1000
#define STR “hello world”
#define定義宏
對于宏不能遞歸
#define SQUARE(x) x*x
int main()
{int r = SQUARE(5);printf("%d ", r); //25return 0;
}
為了避免以下情況發生
#define SQUARE(x) x*x
int main()
{int r = SQUARE(5+1);// r = 5 + 1*5 + 1 printf("%d ", r); //11return 0;
}
可以define成
#define SQUARE(x) ((x)*(x))
#define PRINT(N,FORMAT) printf("the value of " #N " is "FORMAT"\n",N) //#會把參數對應的轉換成字符串
int main()
{int a = 10;PRINT(a,"%d"); //the value of a is 10double b = 3.14;PRINT(b, "%lf"); //the value of b is 3.140000return 0;
}
// ##可以把位于它兩邊的符號合成一個符號#define CAT(Class,Num) Class##Num
int main()
{int class106 = 100;printf("%d", CAT(class, 106)); //100return 0;
}
#define M 100
int main()
{int a = M;
#undef Mreturn 0;
}
//offsetof宏模擬實現
struct s
{char c1;int i;char c2;
};#define OFFSETOF(type,m_name) (size_t)&(((type*)0)->m_name)
int main()
{struct s s = { 0 };printf("%d\n", offsetof(struct s, c1)); //0printf("%d\n", offsetof(struct s, i)); //4printf("%d\n", offsetof(struct s, c2)); //8printf("%d\n", OFFSETOF(struct s, c1)); //0printf("%d\n", OFFSETOF(struct s, i)); //4printf("%d\n", OFFSETOF(struct s, c2)); //8return 0;
}