位操做面試
位操做的必要性:經過串口或並口與其餘器件相連函數
&按位與優化
|按位或spa
^按位異或:兩位相異時爲1,相同時爲0.日誌
上述三個操做知足結合律和交換率。遞歸
左移運算符:<<將要運算的二進制位左移編譯器
規則:高位丟棄,低位補0.數學
使用格式:io
int a = 1<<1;編譯
a = 2;
右移運算符:>>講要運算的二進制右移
規則:高位補符號位,地位丟棄。
符號位:若爲正數則符號位是0,負數符號位爲1。
小技巧:
左移n位至關於乘以2的n次方,但效率比數學運算高。
右移n位至關於除以2的n次方,但效率比數學運算高。
防錯準則:
避免位操做運算符,邏輯運算符和數學運算符同出如今一個表達式中
當位運算符,邏輯運算符和數學運算符須要同時參與運算時,儘可能使用括號()來表達計算次序。
嵌入式比較講究效率!
加減法的優先級高於左移和右移。
交換兩個變量:利用#define和\代碼塊替換
#define SWAP1(a,b) \
{ \
int temp = a; \
a = b; \
b = temp; \
} \
#define SWAP2(a,b) \
{ \
a = a + b; \
b = a - b ; \
a = a - b ; \
} \
問題:若是a很大,b很大,a+b的值可能會使a溢出。
#define SWAP3(a,b) \
{ \
a = a ^ b; \
b = a ^ b ; \
a = a ^ b ; \
} \
位運算符的效率比加減高得多,整數交換建議用第三種方法。
某個面試題:
有一個數列,其中的天然數都是以偶數的形式存在,只有一個天然數出現的次數爲奇數次,找出這個數。
貪心法——++,--表達式閱讀技巧
1.編譯器處理的每一個符號應該儘量多的包含字符
2.編譯器從左像右一個一個儘量多的讀入字符
3.立即將讀入的字符不可能和已讀入的字符組成合法符號爲止。
程序編譯的四個步驟:
由.c和.h文件通過預處理cpp產生.i文件,再通過編譯器gcc,產生.s文件,通過彙編器as產生.o文件,.o和.a文件通過連接器產生.out文件。
預編譯階段:
處理掉全部註釋,用空格代替。
將#define刪除,展開全部的宏
處理條件編譯指令#if,#ifdef,#elif,#else,#endif.
處理#include,展開被包含的文件
保留編譯器須要使用的#pragma指令
預處理指令:gcc-E file.c-o hello.i
編譯階段:
對預處理文件進行一系列的詞法分析,語法分析和語義分析
詞法分析:關鍵字,標示符,當即數等
語法分析:表達式是否遵循語法會澤
語義分析:在語法分析的基礎上進一步分析
生成.i文件
分析結束後,進行代碼優化生成相應的彙編代碼文件
編譯指令: gcc-S file.c -o hello.s
生成.s文件。
連接器:將.o文件和庫文件裝載在一塊兒,生成最終可執行文件。
與源代碼密切相關的,預處理,編譯,彙編。
連接器
做用:把各個模塊之間相互引用的部分處理好,使個個模塊正確銜接。
#define定義宏常量能夠出如今代碼的任何地方
#define從本行開始,以後的代碼均可以使用這個宏常量。
#define 別名 原內容
#define 路徑用法:
#define PATH_1 D:\XYZ\test.c
#define表達式有函數調用的假象,卻不是
#define表達式能夠比函數更強大
#define表達式比函數更容易出錯
printf(「%d\n」,((i++<j) ? (i++) : (j)));
宏表達式在預編譯期被處理,編譯器不知道宏表達式的存在
宏表達式用「實參」徹底替代形參,不進行任何計算。
宏表達式沒有任何「調用」開銷
宏表達式不能出現遞歸定義
宏定義的範圍
#define X 256
//如下可以使用,直到#undef X
#undef X
強大的內置宏
宏 含義 示例
_FILE_ 被編譯的文件名 file1.c
_LINE_ 當前行數 25
_DATE_ 編譯時日期 Jan312012
_TIME_ 編譯時時間 17:01:01
_STDC_ 是否遵循標準C規範 1
定義日誌宏
若是用函數來寫日誌:
void log(char* s)
{
printf(「%s %d %s\n」,_FILE_,_LINE_,s); //行
}
若是在文件中不停調用這個函數,會發現顯示的第二個數據一直爲函數定義時的行數。
由於要調用這個函數時,須要跳回函數執行,這樣只會輸出定義函數時的行數。
這時須要用到宏定義
#define LOG(s) \printf(「%s %d %s\n」,_FILE_,_LINE_,s);
這幾個信息不夠,還須要加上時間
先包含時間頭文件,#include 「time.h」
void f()
{
time_t t;
struct tm* ti;
time(&t);
ti = localtiome(&t);
printf(「%s %d %s」,asctime(ti),_LINE_,_FILE_,s);
}
如何將這個函數加到宏定義
#define LOG(s) do{ \
time_t t; \
struct tm* ti; \
time(&t); \
ti = localtime(&t); \
printf(「%s [%s %d],%s」,asctime(ti),_FILE_,_LINE_,s); \
}while(0);
牛叉的續行符!
課後思考:
#define f (x) ((x)-1)
宏表明什麼意思?對空格敏感麼?宏「調用」對空格敏感麼