C進階2
enum:可定義真正意義上的常量
sizeof:編譯器的內建指示符;用於計算型別或變數所佔的記憶體大小;
sizeof 的值在編譯期就已經確定,不參與程式的執行。
sizeof(var)或sizeof var;不是函式。
例:int var = 0;
int size = sizeof(var++);
printf(“var=%d,size = %d\n”,var,size);
結果為:0,4。var得不到執行。
例:
int f() { printf("dddd\n"); return 0; } int main () { int var = 0; int size = sizeof (var++); printf("var =%d,size =%d\n",var,size); size = sizeof(f()); printf("size = %d\n",size); return 0; }
執行結果並無打印出dddd,因sizeof非函式在程式編譯時就已經替換成了數值。
//-----------------------
typedef:用於給一個已經存在的資料型別重新命名;本質上不能產生新的型別;
其重新命名的型別:可以在typedef語句之後定義,不能被unsigned和signed修飾。
用法:typedef type new_name;
//------------------------------------------
註釋符號:\接續符,常用於巨集定義塊,減少一行的長度。
單引號和雙引號:“a”+1表示指標的運算;
char c = “string”;//編譯後字串“string”的記憶體地址被賦值給變數C;
記憶體地址佔用4個位元組,而變數C只佔用1個位元組,由於型別不同賦值後產生截斷。
//--------------------------------------------
!只認得0,見了0就返回1;碰見的值不是0時,結果為0。
在&&與||混合運算時,整個表示式被看作||表示式,從左向右先計算&&表示式,從左向右先計算&&表示式最後計算||表示式。
交換兩個變數的值採用異或操作。
邏輯運算||和位運算|兩回事。
四則運算>位運算>邏輯運算
//-----------------------------------------
●三目運算子:遵循隱式轉換規則。
a?b:c 當a的值為真時返回b的值,否則返回c的值;返回的是一個值不是變數。
(a<b ? a : b)=3;此式錯誤。*(a<b ? &a : &b)=3;此式正確。
●逗號表示式:連線語句,分號結束為一個語句。
//-------------------------------
編譯過程:預處理、編譯、彙編、連結。
預處理:處理註釋,巨集以及已經以#開頭的符號。
編譯:進行詞法分析,語法分析和語義分析等。
彙編:將彙編程式碼翻譯為機器指令的目標檔案。
連結是指將目標檔案最終連結為可執行程式;
靜態連結:目標檔案直接連結進入可執行程式
動態連結:在程式啟動後才動態載入目標檔案。
//------------------------------
可變引數:
push_test(const char *format,…)
…可變引數,format固定引數。
//-----------------------------
define字面量與const常量不同,它不佔記憶體。
#include <stdio.h> #include "product.h" #if DEBUG #define LOG(s) printf("[%s:%d] %s\n", __FILE__, __LINE__, s) #else #define LOG(s) NULL #endif #if HIGH void f() { printf("This is the high level product!\n"); } #else void f() { } #endif int main() { LOG("Enter main() ..."); f(); printf("1. Query Information.\n"); printf("2. Record Information.\n"); printf("3. Delete Information.\n"); #if HIGH printf("4. High Level Query.\n"); printf("5. Mannul Service.\n"); printf("6. Exit.\n"); #else printf("4. Exit.\n"); #endif LOG("Exit main() ..."); return 0; }
//------------------------------------
條件編譯:
#if、#else、#endif被預編譯器初始,而if……else……語句被編譯器處理。
#erro用於生成一個編譯錯誤訊息,用法:#erro message;message不需要用雙引號包圍
#error預編譯器
#pragma back記憶體對齊
例子:
#include <stdio.h>
#pragma pack(8)
struct S1 // 對齊引數 偏移地址 大小
{
short a; // 2 0 2
long b; // 4 4 4
};
struct S2
{
char c; // 1 0 1
struct S1 d; // 4 4 8
double e; // 8 16 8
};
#pragma pack() // 預設為4
int main()
{
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
return 0;
}
注:gcc不支援8位元組對齊。struct佔用的記憶體大小
第一個成員起始於0偏移處;每個成員按其型別大小和pack引數中較小的
一個進行對齊:偏移地址必須能被對齊引數整除;結構體成員的大小取其
內部長度最大的資料成員作為其大小。結構體長度必須為所有對齊引數的整數
倍。編譯器預設情況下按照四位元組對齊。
//---------------------------------------------
#運算子用於在預處理期將巨集引數轉換為字串
##運算子用於在預處理期粘連兩個識別符號
編譯器不知道#和##運算子的存在。
①
#define connect(a,b) a##b
int connect(a,1); //int a1;
a1=2;
②
#include <stdio.h>
#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type
STRUCT(Student)
{
char* name;
int id;
};
int main()
{
Student s1;
Student s2;
s1.name = "s1";
s1.id = 0;
s2.name = "s2";
s2.id = 1;
printf("s1.name = %s\n", s1.name);
printf("s1.id = %d\n", s1.id);
printf("s2.name = %s\n", s2.name);
printf("s2.id = %d\n", s2.id);
return 0;
}
注:
typedef struct _tag_student student;
struct _tag_student
{};
//------------------------------------
利用指標交換變數:
#include<stdio.h>
int swap (int* a,int* b)
{
int c = *a;
*a = *b;
*b = *c;
}
int main ()
{
int aa = 1;
int bb = 2;
swap(&aa,&bb);
printf("aa = %d\n,bb = %d\n",aa,bb);
return 0;
}
注:const int* p; //p可變,p指向的內容不可變
int const* p; //p可變,p指向的內容不可變
int* const p; //p不可變,p指向的內容可變
const int* const p;//p和p指向的內容都不可變
//------------------------------
a[n]–(a+n)–(n+a)–n[a]
a與&a的區別:
a為陣列首元素的地址;&a為整個陣列的地址;a和&a的區別在於指標運算。
a+1—>(unsigned int)a+sizeof(a) 步長一個元素的大小
&a+1–>(unsigned int)(&a)+sizeof(&a)步長一個數組的大小
(unsigned int)(&a)+sizeof(a)
題:int a[5]={1,2,3,4,5};
int* p1 =(int*)(&a+1);
int* p2 =(int*)((int)a+1);
int* p3 =(int*)(a+1);
問:p1[-1]:(p1-1)–>陣列地址加1–>結果為5
p2[0]: p2–>
注int a[5] 10002000300040005000
陣列a的地址值轉為int型加1,即地址值加1,指向1後面的0,取四個位元組。
結果為0x02000000即…
p3[1]:p3指向a+1,(p3+1)為3.
//----------------------------------
陣列作為函式引數時,編譯器將其編譯成為對應的指標:
void f(int a[]);<–>void f(int a);
void f(int a[5]);<–>void f(int* a);