爲現有類型建立一個新的名字, 使用最多的地方是建立易於記憶的類型名
typedef int size;此聲明定義了一個 int 的同義字,名字爲 sizelinux
想看http://baike.baidu.com/view/1283800.htmc++
第12題:考查typedef類型定義,函數指針面試
例1:typedef int (*test) ( float * , float*)
test tmp;數組
tmp 的類型是
(a) 函數的指針,該函數以 兩個指向浮點數(float)的指針(pointer)做爲參數(arguments)
Pointer to function of having two arguments that is pointer to float
(b) 整型
(c) 函數的指針,該函數以 兩個指向浮點數(float)的指針(pointer)做爲參數(arguments),而且函數的返回值類型是整型
Pointer to function having two argument that is pointer to float and return int
(d) 以上都不是緩存
另一例:安全
typedef void(*ptr_tp_func)(int);/*它表示ptr_tp_func是函數指針,該函數接受一個int參數,返回值為void*/網絡
ptr_tp_func signal(int, ptr_tp_func);/*表示signal是一個函數,接受兩個參數,一個int和一個ptr_tp_func,返回值是ptr_tp_func類型*/函數
1、統計i有多少位爲1:for( ; i ; i&=i-1) k++;性能
2、宏寫出swap(x,y):測試
#define swap(x,y)
x=x+y; y=x-y; x=x-y;
三、一句實現判斷x是否是2的若干次冪:x&(x-1)?false:true;
四、實現左移循環移n位:a=(a<<n)|(a>>(8*sizeof(int)-n));
五、快速求一個數的7倍:X<<3-X
#define 定義宏
#undef 取消已定義的宏
#if 若是給定條件爲真,則編譯下面代碼
#ifdef 若是宏已經定義,則編譯下面代碼
#ifndef 若是宏沒有定義,則編譯下面代碼
#elif 若是前面的#if給定條件不爲真,當前條件爲真,則編譯下面代碼
#endif 結束一個#if……#else條件編譯塊
#error 中止編譯並顯示錯誤信息
1、 有10個指針的數組 int *p[10];
int (*p)[10]中p是一個指針。它的類型是:指向int x[10]這樣的一維數組的指針。
指向函數的指針,函數有一個整型參數並返回一個整數型 int (*p)(int);
一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數 int (*p[10])(int);
二、char a[9]="abcdefg"; char *p="abcdefg";
其它區別:1.指針保存數據的地址,如p保存的是常量字符串「abcdefg」地址,對p內容的修改是非法的 ;數組保存的是數據,對數組的內容能夠直接修改。
1、const
1)做用:a.告知參數的應用目的
b.使優化器產生緊湊的代碼
c.保護不但願被改變的參數:防止參數意外改變
2)例子:a. const int a; a是一整型常量
b. int const a; 同上
c. const int *a; 指針a指向的內容不可變
d. int * const a;指針a指向的內容可變,但指針不可變
e. int const * a const; 都不可變
面試的問題:
a.一個參數既能夠是const又是volatile嗎?
b.一個指針能夠是volatile嗎?
答:a.能夠,例子:只讀的狀態寄存器,它是volatile由於可能被意想不到的改變,是const由於不但願程序試圖去改變它。
b.能夠。一個例子是中斷服務子程序修改一個指向一個buffer的指針時。
此類考題記住volatile型變量可能隨時改變便可。
2、restrict
restrict關鍵字容許編譯器優化某部分代碼以更好地支持計算。它只能用於指針,代表該指針是訪問該對象惟一且初始的方式。
int ar[10];
int * restrict restar= (int *) malloc(10 * sizeof(int));
int * par= ar;
for (n=0; n<10; n++) {
par[n]+=5;
restar[n] +=5;
ar[n] *=2;
par[n] +=3;
restar[n] +=3;
}
restar是訪問它所指向的數據塊的惟一且初始的方式,編譯器能夠把涉及restar的兩條語句替換成下面的語句,效果相同:
restar[n] +=8;/*能夠進行替換*/
三、register
register關鍵字請求讓編譯器將變量a直接放入寄存器裏面,以提升讀取速度,由於register變量可能不存放在內存中,在C語言中register關鍵字修飾的變量不能夠被取地址,可是c++中進行了優化。
1、類型不一樣的操做數運算,精度向低級自動轉換。無符號+有符號=無符號
2、.設 int a=12,則執行完語句 a+=a-=a*a後,a的值是-264.
全部的賦值符(包括複合賦值)都具備右結合性,就是在表達式中最右邊的操做最早執行,而後從右到左依次執行。
3、c中函數參數默認是從右向左壓棧的,printf計算參數時也是
int arr[]={6,7,8,9,10}; int *ptr=arr; *(ptr++)+=123;
printf("%d,%d\n",*ptr,*(++ptr));結果爲8
即printf內的參數從右向左運算。
4、位運算要考慮機器字長,算術運算符優先級高於移位運算符
unsigned char = 0xA5; unsigned char b = ~a>>4+1; 則b爲250.
5、三個float:a,b,c .問值 (a+b)+c==(b+a)+c 和(a+b)+c==(a+c)+b
不必定相等,float存在大數淹沒小數的狀況,如
float a=100000000000,b=-100000000000,c=0.00000000001;
cout < <a+b+c < <endl;
cout < <a+c+b < <endl;
結果是1e-011和0;
儘可能把數量級相近的數先相加
大端模式:是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址中。arm、powerpc
小端模式:是指數據的高字節保存在內存的高地址中,而數據的低字節保存在內存的低地址中。intelx86
大小端測試程序1:
int checkSystem( )
{union check
{int i; char ch;
}c; c.i=1; return (c.ch==1);
}
測試大小端的程序2:
在使用little endian的系統中 這些函數會把字節序進行轉換:
define HTONS(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
ltons 把unsigned short類型從主機序轉換到網絡序
htonl 把unsigned long類型從主機序轉換到網絡序
ntohs 把unsigned short類型從網絡序轉換到主機序
ntohl 把unsigned long類型從網絡序轉換到主機序
在使用big endian類型的系統中 這些函數會定義成空宏。
利用linux中自帶的宏進行判斷:
#if __BYTE_ORDER == __LITTLE_ENDIAN
// 小頭字節序
#elif __BYTE_ORDER == __BIG_ENDIAN
// 大字節序
1、申請內存的函數
void *calloc ( size_t num_elements, size_t element_size );
void *realloc (void *ptr, size_t new_size );
realloc函數用於修改一個原先已經分配的內存塊的大小,可使一塊內存的擴大或縮小。當起始空間的地址爲空,即*ptr = NULL,則同malloc。calloc與malloc相比:calloc分配的內存被初始化爲0,calloc兩個參數:元素個數,元素大小。
2、內存分佈
BSS段:未初始化的全局變量和靜態變量;數據段:初始化的全局變量和靜態變量;代碼段(或文本段):可執行文件的指令;局部變量運行時建立並存儲於棧,函數結束即釋放;靜態變量和全局變量則在程序結束後釋放;可執行文件中包含BSS段所須要的大小,但不是BSS段,堆棧等在程序運行時建立
1、 找出下面一段ISR的問題。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
1)ISR不能傳遞參數。
2)ISR不能有返回值。
3)ISR應該短且有效率,在ISR中作浮點運算不明智。
4)ISR中不該該有重入和性能上的問題,所以不該該使用pintf()函數。
不可重入函數不能夠在它尚未返回就再次被調用。例如printf,malloc,free等都是不可重入函數。由於中斷可能在任什麼時候候發生,例如在printf執行過程當中,所以不能在中斷處理函數裏調用printf,不然printf將會被重入。 函數不可重入大多數是由於在函數中引用了全局變量。例如,printf會引用全局變量stdout,malloc,free會引用全局的內存分配表。
一個鏈表不知道頭結點,有一個指針指向其中一個結點,請問如何刪除這個指針指向的結點:將這個節點複製成下一個節點的值,而後刪除下一個節點
typedef struct LinkList {
int Element;
LinkList * next;
}LinkList;
初始化:
linklist * List_init(){
linklist *HeadNode= (linklist*)malloc(sizeof(linklist));
if(HeadNode == NULL) {
printf("空間緩存不足");
return HeadNode;
}
HeadNode->Element= 0;
HeadNode->next= NULL;
Return HeadNode;
}
建立鏈表:
void CreatList(linklist *HeadNode,int *InData,int DataNum)
{
int i = 0;
linklist *CurrentNode = (linklist*) HeadNode;
for(i = 0;i<DataNum;i++)
{
CurrentNode->Element = InData[i];
if(i< DataNum-1)// 因爲每次賦值後須要新建結點,爲了保證沒有多餘的廢結點
{
CurrentNode->next =(linklist *)malloc(sizeof(linklist));
CurrentNode= CurrentNode->next;
}
}
CurrentNode->next= NULL;
}
插入節點:
bool InsertList(linklist *HeadNode,int LocateIndex,int InData){
int i=1;// 因爲起始結點HeadNode是頭結點,因此計數從1開始
linklist *CurrentNode= (linklist *) HeadNode;
//將CurrentNode指向待插入位置的前一個結點(index -1)
while(CurrentNode&& i<LocateIndex-1){
CurrentNode= CurrentNode->next;
i++;
}
linklist *NodeToInsert=(linklist*)malloc(sizeof(linklist));
if(NodeToInsert == NULL){
printf("空間緩存不足");
return ERROR;
}
NodeToInsert->Element= InData;
NodeToInsert->next = CurrentNode->next;
CurrentNode->next = NodeToInsert;
return OK;
}
具體參考:https://blog.csdn.net/u012531536/article/details/80170893
內聯函數(inline) |
帶參數的宏 |
編譯(彙編)時展開 |
預編譯時替換 |
嚴格的參數類型檢查 |
簡單的替換 |
函數體不能太大,不能包含大循環和遞歸 |
沒要求 |
當編譯器發現某段代碼在調用一個內聯函數時,它不是去調用該函數,而是將該函數的代碼,整段插入到當前位置。這樣作的好處是省去了調用的過程,加快程序運行速度。內聯函數適用於函數體較小且頻繁使用的函數,調用時進行代碼的複製,無需跳轉、入棧等操做,以空間換時間並且由於函數有嚴格的參數類型檢查,比宏要安全;內聯函數在編譯時不單獨產生代碼 。