版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、嵌入式系統(tǒng)程序設(shè)計大連理工大學軟件學院嵌入式系統(tǒng)工程系賴曉晨C/C+語言摘要C語言的歷史和特點預(yù)處理程序位運算函數(shù)指針C程序的移植一、C語言的歷史和特點C語言的歷史C語言的特點C語言的優(yōu)良特性結(jié)構(gòu)化語言,代碼數(shù)據(jù)分離包含指針特性,允許對地址操作語法簡潔緊湊,但功能強大編程方便,運行速度快支持分離編譯C語言的缺點封裝性不如C+,數(shù)據(jù)安全性上有缺陷 類型檢查機制相對薄弱 指針的操作帶來許多不安全因素 比其他高級語言較難掌握二、預(yù)處理程序C89規(guī)定的預(yù)處理指令有以下幾條#if#ifdef#ifndef#else#elif#endif#define#undef#line#error#pragma#in
2、clude預(yù)處理語句的書寫規(guī)則作用:對源程序編譯之前做一些處理,生成擴展C源程序格式:“#”開頭占單獨書寫行語句尾不加分號1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)如 #define YES 1 #define NO 0 #define PI 3.1415926 #define OUT printf(“Hello,World”);1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)
3、代替字符序列(宏體)宏體可缺省,表示宏名定義過如 #define YES 1 #define NO 0 #define PI 3.1415926 #define OUT printf(“Hello,World”);1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)定義位置:任意(一般在函數(shù)外面)作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)定義位置:任意(一般在函數(shù)外面)作用域:從定義命令
4、到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名例 #define ID 1 main() #undef ID #define ID 0 max() YES原作用域YES新作用域如 if(x=YES) printf(“correct!n”); else if (x=NO) printf(“error!n”);展開后: if(x=1) printf(“correct!n”); else if (x=0) printf(“error!n”);1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)宏展開:預(yù)編譯時,用宏體替換宏
5、名-不作語法檢查定義位置:任意(一般在函數(shù)外面)作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)宏展開:預(yù)編譯時,用宏體替換宏名-不作語法檢查定義位置:任意(一般在函數(shù)外面)作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名引號中的內(nèi)容與宏名相同不置換例 #define ID 1 語句printf( ID );會輸出ID,而非11. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)
6、代替字符序列(宏體)宏展開:預(yù)編譯時,用宏體替換宏名-不作語法檢查定義位置:任意(一般在函數(shù)外面)作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名宏定義可嵌套,不能遞歸例 #define ID ID + 1 ()引號中的內(nèi)容與宏名相同不置換例 #define DIS1 10 #define DIS2 DIS1+10 var=DIS2*2;宏展開:var= 10+10 *2;1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)宏展開:預(yù)編譯時,用宏體替換宏名-不作語法檢查定義位置:任意(一般在函數(shù)外面)
7、作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名宏定義可嵌套,不能遞歸引號中的內(nèi)容與宏名相同不置換宏定義中使用必要的括號()例 #define DIS1 10 #define DIS2 (DIS1+10) var=DIS2*2;宏展開:var= (10+10) *2; 1. 宏定義不帶參數(shù)宏定義一般形式: #define 宏名 宏體功能:用指定標識符(宏名)代替字符序列(宏體)宏展開:預(yù)編譯時,用宏體替換宏名-不作語法檢查定義位置:任意(一般在函數(shù)外面)作用域:從定義命令到文件結(jié)束#undef可終止宏名作用域 格式: #undef 宏名宏定義可嵌套,不能遞歸
8、引號中的內(nèi)容與宏名相同不置換宏定義中使用必要的括號()宏體可以省略,表示宏名已被定義過/* ch3_1.c*/#include #define Aint main()#ifdef Aprintf(A has been definedn); #elseprintf(A has not been definedn); #endifreturn 0;輸出為:“A has been defined”,即使把宏定義改為:#define A0輸出仍舊為:“A has been defined”。帶參數(shù)宏定義一般形式: #define 宏名(參數(shù)表) 宏體例 #define T (m, n) m*n相當于定
9、義了不帶參宏T,其宏體為“(m, n) m*n” 宏展開:形參用實參換,其它字符保留例 #define T(m,n) m*n . area=T(3,2);宏展開: area=3*2;不能加空格帶參數(shù)宏定義一般形式: #define 宏名(參數(shù)表) 宏體宏展開:形參用實參換,其它字符保留宏體及各形參外一般應(yīng)加括號()例 #define T(m,n) m*n . area=T(3,2);宏展開: area=3*2;例 #define CUBE(x) x*x*x a=4; b=6; z=CUBE(a+b);宏展開:z=a+b*a+b*a+b;一般寫成: #define CUBE(x) (x)*(x)
10、*(x)宏展開: z=(a+b)*(a+b)*(a+b);#define FUNC(x,y) (x)(y)?(x):(y) .main() int a,b,c,d,t; . t=FUNC(a+b,c+d); 宏展開:t=(a+b)(c+d)?(a+b):(c+d);int func(int x,int y) return(xy?x:y);main() int a,b,c,d,t; . t=func(a+b,c+d); 例 用宏定義和函數(shù)實現(xiàn)同樣的功能帶參的宏與函數(shù)區(qū)別帶參宏函數(shù)處理過程不分配內(nèi)存簡單的字符置換分配內(nèi)存先求實參值,再代入形參處理時間編譯時程序運行時參數(shù)類型無類型問題定義實參,形參
11、類型程序長度變長不變運行速度不占運行時間調(diào)用和返回占時間Embest開發(fā)環(huán)境中的宏定義44b.h有44B0X中各個特殊功能寄存器的宏定義#define rBWSCON(*(volatile unsigned *)0 x1c80000)#define rBANKCON0(*(volatile unsigned *)0 x1c80004)#define rBANKCON1(*(volatile unsigned *)0 x1c80008)#define rBANKCON2(*(volatile unsigned *)0 x1c8000c)#define rBANKCON3(*(volatile u
12、nsigned *)0 x1c80010)#define rBANKCON4(*(volatile unsigned *)0 x1c80014)#define rBANKCON5(*(volatile unsigned *)0 x1c80018)預(yù)定義宏C89規(guī)范了五個固有的預(yù)定義宏,分別為:_LINE_:行號_FILE_:文件名_DATE_:日期_TIME_:時間_STDC_:1標準C編譯器 0非標準C編譯器預(yù)定義宏#include int main()printf(The current file is: %sn, _FILE_);printf(The current line numbe
13、r is: %dn, _LINE_);printf(today is: %sn, _DATE_);printf(the time is: %sn, _TIME_);if(_STDC_ = 1)printf(this is a standard compilern);else if(_STDC_ = 0)printf(this is not a standard compilern);/exp/pre/macro.c功能:對源程序中的一部分內(nèi)容只有滿足某種條件的情況下才進行編譯。2. 條件編譯#ifdef 標識符程序段1#else程序段2#endif形式1:當標識符已經(jīng)被定義過(使用#defin
14、e),則對程序段1進行編譯,否則編譯程序段2。其中#else部分可以省略。形式1(續(xù)):#define IBM-PC 0 /*或 #define IBM-PC */。#ifdef IBM-PC#define INT 16#else#define INT 32#endif可以用來提高程序的可移植性形式1(續(xù)):#define DEBUG .#ifdef DEBUGprintf(“x=%d, y=%d”,x,y);#endif可以用來調(diào)試程序調(diào)試結(jié)束后只需將define行刪掉即可#ifndef 標識符程序段1#else程序段2#endif形式2:當標識符未被定義過,則對程序段1進行編譯,否則編譯程
15、序段2。(與形式1正相反)#if 表達式程序段1#else程序段2#endif形式3:當表達式為真時,則對程序段1進行編譯,否則編譯程序段2。 #include #define CAP 1int main()char string20=I love China;char c; int i=0;c=stringi+;while(c!=0)#if CAPif(c=a&c=z)c-=32;#endifprintf(%c,c);c=stringi+;printf(n);return 0;形式3:(續(xù))3. 文件包含功能:一個源文件可將另一個源文件的內(nèi)容全部包含進來一般形式: #include “文件名
16、” 或 #include 直接按標準目錄搜索“” 先在當前目錄搜索,再搜索標準目錄可指定路徑3. 文件包含功能:一個源文件可將另一個源文件的內(nèi)容全部包含進來一般形式: #include “filename” 或 #include 處理過程:預(yù)處理時,用被包含文件的內(nèi)容取代該預(yù)處理命令,再把“包含”后的文件作為一個源文件編譯被包含文件內(nèi)容源文件(*.c)頭文件(*.h)宏定義數(shù)據(jù)結(jié)構(gòu)定義函數(shù)說明等實際上文件名也可以是C源文件,不過這不是良好的編程風格【例3-5】文件包含一下程序包含一個完整的模塊(function.c、function.h、test.c) /*funtion.h*/#ifndef
17、 _FUNCTION#define _FUNCTIONvoid f();#endif/*function.c*/#include void f()printf(a example of #include.n);/*test.c*/#include #include function.hint main()f();return 0; 頭文件格式4. 其他預(yù)處理指令#error指令強制編譯器停止編譯,主要用于程序調(diào)試。#error指令的一般形式為:編譯到#error時,會顯示相應(yīng)字符串#error error-message#error舉例#define CON10#define CON21#de
18、fine CON3-1int main()#ifCON1#ifCON2#error run to position1#else#error run to position2#endif#else#ifCON3#error run to position3#else#error run to position4#endif#endif明確程序編譯位置三、位運算位運算符按位與&取反按位或|左移1. 位與&運算規(guī)則:兩個位都為1,結(jié)果為1,否則為0例如:9&0 x0c結(jié)果為82. 位或|運算規(guī)則:兩個位都為0,結(jié)果為0,否則為1例如:9|0 x0c結(jié)果為0 x0d3. 按位取反運算規(guī)則:1變0,0變
19、1用途:使某位取反3. 按位取反 (續(xù))例:使某數(shù)最低位為0int a;a=a&0 xfffffffe3. 按位取反 (續(xù))例:使某數(shù)最低位為0思考:有沒有隱含的問題int a;a=a&0 xfffffffe3. 按位取反 (續(xù))例:使某數(shù)最低位為0/* 16位機 */int a;a=a&0 xffffe/* 32位機 */a=a&0 xfffffffe可移植性變差3. 按位取反 (續(xù))例:使某數(shù)最低位為0a=a&1/* 1能自動適應(yīng)16位機以及32位機 */解決辦法4. 按位異或運算規(guī)則:判斷兩位是否相同,同則為0,否則為1用途:使特定位翻轉(zhuǎn) 交換兩個值,不用臨時變量4. 按位異或 (續(xù))不
20、通過中間變量交換兩個變量的值/*ch3_7.c*/#include int main()int a=21;int b=43;a=ab;b=ba;a=ab;printf(a=%d, b=%dn,a, b);return 0; 5. 左移位運算規(guī)則:將一個數(shù)的全部二進制位右移若干位,移出位舍棄,左側(cè)可能補0或者補1,視計算機系統(tǒng)不同而不同。符號問題:無符號數(shù)右移,左側(cè)補0有符號數(shù)視計算機系統(tǒng)而定:邏輯右移、算術(shù)右移例:循環(huán)右移n位10011111110010101001111111001010N位例:循環(huán)右移n位(續(xù))#include int main()unsigned a,b,c,n;scan
21、f(a=%x,n=%d,&a,&n);b=an;c=c|b;printf(a=%x,c=%xn,a,c);return 0;輸入:a=0 x12345678,n=8顯示:a=12345678,c=78123456四、函數(shù)指針 每一個函數(shù)模塊都有一個首地址,稱為函數(shù)的入口地址。 指向函數(shù)的指針稱為函數(shù)指針,保存的是函數(shù)的入口地址(首地址) 函數(shù)調(diào)用:找到函數(shù)入口地址;傳遞參數(shù) 1. 函數(shù)指針的定義方法格式:int (*ptr1)(int);定義了函數(shù)指針ptr1,此指針只能保存具有一個整型參數(shù)的整型函數(shù)的首地址。注意 :int *ptr1(int);這是一條函數(shù)聲明語句,表示一個帶有整數(shù)參數(shù)的函
22、數(shù)返回,返回一個整型指針。int (*ptr1)(int); 這個是函數(shù)指針例:以0.1為步長,計算特定范圍內(nèi)的三角函數(shù)之和。sin(0.1)+sin(0.2)+sin(1.0)cos(0.5)+cos(0.6)+cos(3.0)#include #include double triangle(double(*func)(double), double begin, double end)double step,sum=0.0;for(step=begin;stepend;step+=0.1)sum+=func(step);return sum;int main() double resul
23、t;result=triangle(sin, 0.1, 1.0);printf(the sum of sin from 0.1 to 1.0 is %fn,result);result=triangle(cos, 0.5, 3.0);printf(the sum of cos from 0.5 to 3.0 is %fn,result);return 0;#include #include double triangle(double(*func)(double), double begin, double end)double step,sum=0.0;for(step=begin;step
24、end;step+=0.1)sum+=func(step);return sum;int main() double result;result=triangle(sin, 0.1, 1.0);printf(the sum of sin from 0.1 to 1.0 is %fn,result);result=triangle(cos, 0.5, 3.0);printf(the sum of cos from 0.5 to 3.0 is %fn,result);return 0;2. 用typedef來簡化函數(shù)指針對參數(shù)較多的函數(shù)類型,定義相應(yīng)的函數(shù)指針比較煩瑣,可用typedef關(guān)鍵字簡化
25、例如typedef double (*FUN)(double a, double b);用typedef來簡化函數(shù)指針(續(xù))格式:int (*ptr1)(int);定義函數(shù)指針的別名方法:定義了函數(shù)指針ptr1,此指針只能保存具有一個整型參數(shù)的整型函數(shù)的首地址。double (*fun1)(double a, double b);typedef double (*FUN)(double a, double b);FUN f1; FUN f2; 用typedef來簡化函數(shù)指針(續(xù))格式:int (*ptr1)(int);定義函數(shù)指針的別名方法:(也可以這樣)定義了函數(shù)指針ptr1,此指針只能保存
26、具有一個整型參數(shù)的整型函數(shù)的首地址。double (*fun1)(double a, double b);typedef double (FUN)(double a, double b);FUN *f1; FUN *f2; 3函數(shù)指針數(shù)組聲明方式定義了表示定義了一個長度為4的函數(shù)指針數(shù)組,同時做了初始化。double ( * fp4 ) (double,double)= f1 , f2 , f3, f4 4函數(shù)指針應(yīng)用在嵌入式操作系統(tǒng)中,經(jīng)常用函數(shù)指針來完成任務(wù)的調(diào)度。例如uC/OS中,任務(wù)創(chuàng)建的函數(shù)原型為第一個參數(shù)為函數(shù)指針I(yè)NT8U OSTaskCreate(void(*task)(voi
27、d*pd), void *pdata, OS_STK *ptos, INT8U prio);五、C程序的移植為一種機器寫的程序,經(jīng)常需要在其他硬件、操作系統(tǒng)的平臺上運行,往往需要對此程序進行一些改動,這個過程叫做程序的移植方便移植的程序稱為可移植程序程序不可移植,主要是因為有太多硬件相關(guān)的代碼1、避免使用“魔數(shù)”“魔數(shù)”(magic number):依賴于系統(tǒng)或處理器的數(shù)字。例如表示硬盤緩沖區(qū)的大小、屏幕和鍵盤的特定尺寸等數(shù)字?!澳?shù)”的出現(xiàn)使系統(tǒng)可移植性變差。下列代碼本質(zhì)上是不可移植的fread(buf, 256, 1, fp); /緩沖區(qū)為256B使用#define替換“魔數(shù)”程序中要盡量
28、避免“魔數(shù)”的硬編碼,可以用宏來取代魔數(shù),使可讀性增強,而且移植程序時只要修改宏一處即可#define BUFFER_SIZE 256fread (buf, BUFFER_SIZE, 1, fp); 例一個圖形處理程序中,需要不同的顏色執(zhí)行不同操作例/*惡劣的例子*/void ShowColor(int color)if ( color = 0 )sub_red();else if ( color = 1 )sub_blue();else if ( color = 2 )sub_green();return ; 例(改進后的程序) /*然后在源文件中直接使用這些宏來判斷*/#include c
29、olor.hvoid ShowColor(int color)if ( color = RED )sub_red();else if ( color = BLUE )sub_blue();else if ( color = GREEN )sub_green();return ; /* color.h*/#define RED 0#define BLUE 1#define GREEN 22、程序分層不同的操作系統(tǒng)為應(yīng)用程序提供了不同的支持,例如windows2000應(yīng)用程序可以有多線程特性,但是windows3.2不可以,應(yīng)用程序?qū)ο到y(tǒng)有依賴型。這種依賴性沒有具體通用的解決方法,但是可以通過程序
30、分層來解決,把系統(tǒng)相關(guān)的代碼放到一起。3、注意數(shù)據(jù)類型的長度16位機中整型數(shù)據(jù)是2字節(jié),32位機為4字節(jié),這會導致程序的不兼容。可以利用宏來重定義數(shù)據(jù)類型#define int16 int/16位機int16 a;#define int16 short int/32位機int16 a;注意數(shù)據(jù)類型的長度(續(xù))16位機中整型數(shù)據(jù)是2字節(jié),32位機為4字節(jié),這會導致程序的不兼容。使用可適應(yīng)任何情況的編碼方式,例如把一個整型數(shù)據(jù)寫入磁盤:fwrite(&i, 4, 1, fp);/不好fwrite(&i, sizeof(int), 1, fp);/好4、對齊問題某些計算機允許數(shù)據(jù)邊界地址不對齊,把這
31、樣的代碼移植到ARM上時要小心。ARMv5TE前的處理器都不支持地址不對齊的指針5、大小端問題如果兩臺計算機的大小端定義不一致,那么代碼移植時要做轉(zhuǎn)換6、枚舉類型enum是可移植的,但是不同編譯器中對enum分配的字節(jié)數(shù)可能不同。不能在不同的編譯器之間對代碼進行交叉連接7、減少內(nèi)嵌匯編C語言的內(nèi)嵌匯編由C編譯器來負責編譯,而不使用armasm或gas。內(nèi)嵌匯編可以提高編程效率,但是會影響到程序的可移植性。C語言與C+語言的區(qū)別變量定義位置結(jié)構(gòu)體變量數(shù)據(jù)類型輸入輸出動態(tài)內(nèi)存分配其他區(qū)別1. 變量定義位置C89要求所有變量都必須定義在塊的最前部C+沒有這個要求,可以在程序任意位置定義新的變量2.
32、結(jié)構(gòu)體變量在C+中,struct結(jié)構(gòu)體支持成員函數(shù)的定義,C中不行。如果在C的struct中定義函數(shù),編譯時會顯示一個“field function name declared as function”錯誤2. 結(jié)構(gòu)體變量(續(xù))/*ch3_10.c*/struct Aint a;int b();int main()struct A c;c.a=2;return 0;編譯錯誤:“ch3_10.c:5: error: field b declared as a function”C+標準可以通過編譯2. 結(jié)構(gòu)體變量(續(xù))在C語言中,聲明一個結(jié)構(gòu)體類型A之后,使用下面的語句來定義結(jié)構(gòu)體變量a:str
33、uct A a;而C+語言中可以省略struct3. 數(shù)據(jù)類型C+中有bool (或boolean類型);C中沒有這樣的bool類型,均為數(shù)值類型!C編譯器不能通過編譯,C+編譯器可以bool a;a = 1;4. 輸入輸出 C中使用printf、scanf輸入輸出使用時不用包含任何頭文件但如果使用g+編譯時必須加上stdio.h頭文件int a;scanf( %d, &a );printf( 您輸入的數(shù)值是%dn, a );A. scanf()函數(shù)功能:從鍵盤讀入指定格式的數(shù)據(jù)格式:scanf( 控制字符串, 輸入項列表 );注意:scanf中各變量一定是表示地址的標識符(加&)控制字符串控
34、制字符串有兩部分組成:格式說明形式:%普通字符空格可打印字符格式說明各格式字符及其意義:(詳見C教程)d:輸入一個十進制整數(shù)o:輸入一個八進制整數(shù)x:輸入一個十六進制整數(shù)f:輸入一個小數(shù)形式的浮點數(shù)e:輸入一個指數(shù)形式的浮點數(shù)c:輸入一個字符s:輸入一個字符串空格在多個輸入時,一般用空格或回車作為分隔符若以空格作為分隔符,當輸入中包含字符類型時,可能產(chǎn)生非預(yù)期的結(jié)果scanf ( %d%c, &a, &ch );輸入:45 q輸出:45 空格空格(續(xù))如下語句會有正確輸出此處%d后的空格,就可以跳過字符q前的所有空格scanf ( %d %c, &a, &ch );輸入:45 q輸出:45 q
35、可打印字符看一個例子輸入為:1,2,q可以得到 a = 1, b = 2, ch = q輸入為:1 2 q除a的值為1外,對b與ch的賦值失敗scanf ( %d,%d,%c, &a, &b, &ch );B. printf()函數(shù)功能:從缺省輸出設(shè)備(一般為顯示器)輸出規(guī)定格式的字符串格式:printf( 控制字符串, 輸入項列表 );控制字符串控制字符串有兩部分組成:格式說明形式:%普通字符空格可打印字符格式說明各格式字符及其意義:(詳見C教程)c:按字符型輸出o:按八進制輸出d:按十進制輸出x:按十六進制輸出u:按無符號整數(shù)輸出f:按浮點型小數(shù)輸出g:按e和f格式中較短的一種輸出e:按科
36、學計數(shù)法輸出普通字符普通字符:可打印字符主要是說明字符,按原樣輸出,支持漢字輸出轉(zhuǎn)義字符(例)不能直接打印,控制產(chǎn)生特殊的輸出效果普通字符(續(xù))轉(zhuǎn)義字符示例i = 789,n = 123, a = 92.34567,且i為整型,n為長整型。 printf( %4dt%7.4fnt%lun, i, a, n );輸出為: 78992.3457 123C語言輸入輸出總結(jié)輸入輸出可能是C和C+的最明顯的區(qū)別C中用scanf(), printf()來完成輸入輸出操作C+中全局對象cin、cout來輸入輸出,比C更方便,而且類型檢查機制更加完善C+中的使用方式new申請delete釋放C中的使用方式ma
37、lloc()申請free()釋放5. 動態(tài)內(nèi)存分配函數(shù)原型:void *malloc( long size );作用:在對內(nèi)存中分配size各字節(jié),并返回了指向這塊內(nèi)存首地址的指針如果分配失敗,返回NULL返回指針為void*型的,要強制轉(zhuǎn)換A. malloc()函數(shù)函數(shù)原型:void free( void *FirstByte );作用:將之前用malloc申請的空間歸還操作系統(tǒng)否則就導致內(nèi)存泄漏編譯器不會發(fā)現(xiàn)內(nèi)存泄漏這樣的錯誤B. free()函數(shù)C. 函數(shù)的用法/*例 3-11*/#include #include int main()int* p;if(p = (int*)malloc
38、(sizeof(int) = NULL )printf(動態(tài)內(nèi)存分配失敗n);exit(1);C. 函數(shù)的用法(續(xù))*p = 100;printf(%dn, *p);free(p);p = NULL;return 0;頭文件:malloc和free被頭文件stdlib.h包含C+中new和delete為關(guān)鍵字,故無需頭文件包含使用:int *p=(int*)malloc(sizeof(int);int *p = new int;與C+的幾點區(qū)別6. 其他區(qū)別常量表示方法不同C語言不支持引用的概念,而C+支持注釋不同,C89不支持單行注釋(+i)+在C中不合法(a=3)=4在C中不合法不能在fo
39、r循環(huán)頭部定義變量GNU C擴展64位整型數(shù)據(jù)類型內(nèi)聯(lián)函數(shù)attribute關(guān)鍵字單行注釋switch case 簡寫預(yù)定義宏結(jié)構(gòu)體和初始化長度為0的數(shù)組64位整型數(shù)據(jù)類型GNU CC(GNU Compiler Collection)定義了64為整型關(guān)鍵字long long,可以直接操作64位數(shù)據(jù)long long int a = 0 x123;expgnu_clong.c內(nèi)聯(lián)函數(shù)減少函數(shù)調(diào)用開銷增加類型檢查,比宏使用更安全inline是建議而非命令attribute關(guān)鍵字關(guān)鍵字attribute通過向GCC指明有關(guān)代碼的更多信息來幫助代碼優(yōu)化工作進行的更好。attribute關(guān)鍵字(續(xù))下面
40、代碼通過使用_attribute_,當t未被使用時編譯器不會警告int main( )float t _attribute_ (unused);return 0;例3-12#include void quit() _attribute_ (noreturn);void quit()exit(1);int test(int n)if ( n 0 )quit();elsereturn 0;int main( )test(1);return 0;函數(shù)不返回【例3-13】/*ch3_13.c*/#include struct s int a2 _attribute_ (aligned (8); ;st
41、ruct tchar a;int b2 _attribute_ (packed); int main()int y _attribute_ (aligned (16);y=1;return 0;以8字節(jié)對齊單行注釋int main()/long long t1;int t4=3;return 0;expgnu_cnote.cswitch case 簡寫/*ch3_14.c*/#include int main()int t=2;/*傳統(tǒng)方式*/switch(t)case 0 :case 1 :case 2 :printf(012n);break;case 3 :case 4 :case 5 :
42、printf(345n);switch case 簡寫/*GCC擴展方式*/switch(t)case 0 . 2 :printf(012n);break;case 3 . 5 :printf(345n);return 0;expgnu_ccase.cgcc允許這樣寫。預(yù)定義宏/*ch3_15.c*/#include void f(void)printf(This is function %s n, _FUNCTION_);int main( )printf(This is function %s n, _FUNCTION_);f();return 0;expgnu_cfunc.c結(jié)構(gòu)體初始化
43、struct file_operations ext2_file_operations =llseek:generic_file_llseek,read:generic_file_read,write:generic_file_write,ioctl:ext2_ioctl,mmap:generic_file_mmap,open:generic_file_open,release:ext2_release_file,fsync:ext2_sync_file,;expgnu_cfunc.c結(jié)構(gòu)體初始化 struct file_operations driver_fops =owner: THIS_
44、MODULE,read: driver_read,open: driver_open,release: driver_release,;其他的值被初始化為0.expgnu_cfunc.c長度為0的數(shù)組GNU還允許結(jié)構(gòu)體的末尾成員是長度為0的數(shù)組錯誤處理機制C語言錯誤處理機制系統(tǒng)日志文件 一、C語言的錯誤處理機制C標準中有幾個錯誤處理機制 預(yù)定義宏預(yù)定義全局變量若干庫函數(shù)1. assert宏assert宏定義在assert.h中語法格式:作用:計算表達式expression的值,如果為0,那么首先向stderr打印一條出錯信息,然后調(diào)用abort()函數(shù)終止程序運行。assert (expres
45、sion)【例3-16】/*ch3_16.c*/#include#include #includeint main()char *p;p = getenv(HOME);assert(p);printf(HOME=%sn,p);p = getenv(NOTEXIST);assert(p);printf(NOTEXIST=%sn,p);return 0;/exp/error/badptr.cassert的缺點assert的調(diào)用會影響程序的運行效率,有時希望程序中的assert不會起作用,這可以通過在程序前部包含assert.h之前定義一個 NDEBUG來實現(xiàn)?!纠?-17】/*ch3_17.c*/
46、#define NDEBUG#include#include #includeint main()char *p;p = getenv(HOME);assert(p);printf(HOME=%sn,p);p = getenv(NOTEXIST);assert(p);printf(NOTEXIST=%sn,p);return 0;/exp/error/badptr2.cassert使用注意事項當使用#define NDEBUG來禁用assert宏時,注意assert宏中隱含的某些操作不能完成,而這些代碼可能對后面的操作有關(guān)鍵作用。定義NDEBUG,p賦值行未執(zhí)行,使用p時出錯。assert使用
47、注意事項舉例#define NDEBUGassert(p=malloc(sizeof(char)*100);free(p);#define NDEBUGp=malloc(sizeof(char)*100);assert(p);free(p);應(yīng)該按照這種方式來編寫P是野指針assert使用討論assert宏只提供了一種粗糙的終止程序運行的方式,這種方法并不理想。理想的方式是“適當?shù)慕导墶?,在不同層次的出錯處理都失敗了,別無選擇的情況下才終止程序的運行。在不得不警告或者提示用戶之前能成功的處理的出錯越多,程序就越健壯。2. 位置指示宏C標準定義了兩個宏:_LINE_FILE_把這兩個宏用于可以更
48、精確的定位程序的出錯位置?!纠?-18】#include #include int show_environment(char* e, int num, char *name)char* p=getenv(e);if(p!=NULL)printf(the environment is: %sn, p);return 0;elseprintf(error occured at %d of %s.n, num,name);return 1; /exp/error/filefcn.c【例3-18】(續(xù))int main()char* e1=HOME;char* e2=NOTEXIST;int res
49、;res = show_environment(e1, _LINE_, _FILE_);if (res)return 1;res = show_environment(e2, _LINE_, _FILE_);if (res)return 1;return 0;/exp/error/filefcn.c3. 標準庫函數(shù)本節(jié)的“標準庫”是指任何支持ANSI/ISO C標準的C環(huán)境的一部分變量、宏、函數(shù)。本節(jié)介紹5個函數(shù)和一個變量。stdlib.h:void abort(void);void exit(int status);int atexit(void (*fcn)(void);stdio.hvo
50、id perror(const char *s);string.hchar *strerror(int errnum);errno.hint errno;3. 標準庫函數(shù)(續(xù))C語言還提供了一些標準庫函數(shù)和全局變量用來支持錯誤處理,具體包含5個函數(shù),以及一個全局變量,任何ANSI/ISO C標準的實現(xiàn)都包含這些特性A. errnoLinux系統(tǒng)調(diào)用和許多庫函數(shù)在出錯時都要把全局變量errno設(shè)置為一個非0值,唯一對應(yīng)一種出錯的情況。在希望通過訪問errno以確定錯誤類型前,要人為的把errno設(shè)置為0,因為沒有任何一個函數(shù)可以把errno設(shè)置為0。errno定義在頭文件stdlib.h中【例3
51、-19】/*ch3_19.c*/#include #include #include #include int main(void)FILE *fp;errno=0;fp=fopen(notexist,r);if(errno)printf(Open file failed.n);elseprintf(Open file successfully.n);/exp/error/errno.c檢測errno值【例3-19】(續(xù))printf(try again. n);errno=0;fp=fopen(notexist,w);if(errno)printf(Open file failed.n);e
52、lseprintf(Open file successfully.n);return 0;檢測errno值/exp/error/errno.c清0變量errno的常見值宏值含義EPERM1操作不被允許ENOENT2文件或目錄不存在ESRCH3進程不存在EINTR4系統(tǒng)調(diào)用中斷EIO5I/O錯誤ENXIO6設(shè)備或地址不存在E2BIG7參數(shù)太長EBADF9錯誤的文件號ECHILD10子進程不存在變量errno的常見值(續(xù))宏值含義EAGAIN11重試ENOMEM12沒有內(nèi)存EACCES13沒有權(quán)限EFAULT14地址錯誤EBUSY 16設(shè)備或資源忙EEXIST17文件存在ENODEV19設(shè)備不存在
53、ENOTDIR20不是目錄EISDIR21是目錄變量errno的常見值(續(xù))宏值含義EINVAL22無效參數(shù)EMFILE24打開的文件太多ENOTTY25不是打印機EFBIG27文件太長ENOSPC28磁盤上沒有空間EPIPE32管道中斷EDOM33數(shù)學參數(shù)超出函數(shù)定義域ERANGE34數(shù)學結(jié)果不可表示EILSEQ84非法字節(jié)序列變量errno的常見值(續(xù))宏值含義ERESTART85中斷的系統(tǒng)調(diào)用應(yīng)該重啟EUSERS87用戶數(shù)太多ANSI/ISO CPOSIXB. abort函數(shù)abort函數(shù)的功能是立刻終止程序運行,并且不會執(zhí)行由atexit()登記過的函數(shù)原型:void abort(vo
54、id);【例3-20】/*ch3_20.c*/#include #include int main(void)printf(Hello everybody.n);abort();printf(you can not get here. n);return 0;/exp/error/boom.cC. exit()函數(shù)exit()函數(shù)于abort()的區(qū)別在于終止程序前會執(zhí)行由atexit()登記的函數(shù)函數(shù)原型:#includevoid exit(int status);exit的類型是void,即沒有返回值。status是exit函數(shù)返回給操作系統(tǒng)的退出碼,可以是任何數(shù)值,而在stdlib.h中
55、定義了兩個宏:EXIT_SUCCESS和EXIT_FAILURED. atexit函數(shù)atexit函數(shù)登記在程序正常結(jié)束時要調(diào)用的函數(shù),或者由exit調(diào)用或者由main函數(shù)返回來調(diào)用。函數(shù)原型:#includeint atexit(void (*function)(void);傳遞給atexit的函數(shù)不帶任何參數(shù),也沒有返回值。如果function登記成功,則atexit返回0,否則返回1。如果執(zhí)行abort函數(shù),則不會調(diào)用atexit登記的函數(shù)?!纠?-21】/*ch3_21.c*/#include #include void test()printf(you can still get h
56、ere. n);int main(void)printf(hello everybody. n);if(atexit(test)!=0)printf(atexit() run failed.n);exit(EXIT_FAILURE);printf(goodbye everybody. n);return 0;E. strerror函數(shù)strerror函數(shù)返回一個指向字符串的指針,該字符串描述了和errnum相對應(yīng)的錯誤信息,如把errnum傳遞給strerror,則可得到此信息。函數(shù)原型:#includechar* strerror(int errnum);F. perror函數(shù)perror函
57、數(shù)輸出系統(tǒng)錯誤信息。函數(shù)原型:#include #include void perror(const char *s);如果系統(tǒng)調(diào)用失敗,一般會設(shè)置errno。perror()函數(shù)首先打印字符串參數(shù)s,然后添加一個冒號和一個空格,然后是對應(yīng)于errno的錯誤信息和一個換行符。F. perror函數(shù)(續(xù))以下兩行等價:perror( “something error”);printf(“something error: %s”,strerror(errno);perror與strerror的比較前者短小精干,完全能應(yīng)付一般使用。后者可以對錯誤信息再編輯,可以應(yīng)用于需要精心設(shè)計的場合【例3-22】
58、/*ch3_22.c*/#include #include #include #include #include int main(void)FILE *fp;char* p;errno=0;fp=fopen(notexist,r);if(errno)perror(Open file);/exp/error/errinfo.c【例3-22】(續(xù))errno=0;fp=fopen(notexist,r);if(errno)p=strerror(errno);fprintf(stderr, Open file: %sn, p);return 0;/exp/error/errinfo.c二、系統(tǒng)日志
59、文件Linux的兩個系統(tǒng)守護進程klogd和syslogd提供了集中的系統(tǒng)日志功能。klogd供內(nèi)核和運行在內(nèi)核空間的程序,特別是設(shè)備驅(qū)動程序使用。syslogd控制著來自用戶空間的消息的產(chǎn)生。日志消息的優(yōu)先級寫入系統(tǒng)日志的消息由它的級別(level)和功能(facility)來控制。級別指出了消息的重要程度和嚴重性功能告訴syslogd守護進程是哪個程序發(fā)出的消息。一條日志消息優(yōu)先級由級別和功能共同組成syslog的日志級別:level級別嚴重性LOG_EMERG系統(tǒng)不可用LOG_ALERT要求立刻處理LOG_CRIT重大錯誤,比如硬盤故障LOG_ERR錯誤條件LOG_WARNING警告錯誤
60、LOG_NOTICE正常但重要的消息LOG_INFO純粹的通報消息LOG_DEBUG調(diào)試跟蹤輸出syslog的功能值:facility功能消息源LOG_AUTHPRIV私有的安全和授權(quán)消息LOG_CRON時鐘守護進程(crond和atd)LOG_DAEMON其他系統(tǒng)守護進程LOG_KERN內(nèi)核消息LOG_LOCAL0-7為本地/站點使用而保留LOG_LPR打印機子系統(tǒng)LOG_MAIL郵件子系統(tǒng)LOG_NEWS新聞組子系統(tǒng)LOG_SYSLOGsyslogd產(chǎn)生的內(nèi)部消息LOG_USER一般用戶級消息(默認)LOG_UUCPuucp子系統(tǒng)發(fā)送消息的原則選取與消息內(nèi)容相適應(yīng)的級別值。對于用戶級程序,
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 招標投資風險與控制
- 婚姻中的互相支持
- 借款合同解除協(xié)議范本
- 招標文件開發(fā)商必讀
- 污水處理項目設(shè)計招標
- 跨國合同保險問題解析
- 防水工程質(zhì)量改進協(xié)議
- 廣發(fā)租房合同續(xù)租條件和流程
- 總公司與分公司合作合同模板
- 實驗室研究技術(shù)服務(wù)合同
- 課本劇西門豹治鄴劇本
- 下肢靜脈血栓形成全解課件
- 《多式聯(lián)運單證》課件
- 宿舍危險源識別和風險評價表范例
- 《尖子生培養(yǎng)》課件
- 特種設(shè)備(承壓類)生產(chǎn)單位安全風險管控(日管控、周排查、月調(diào)度)清單
- 網(wǎng)絡(luò)傳播法規(guī)(自考14339)復(fù)習必備題庫(含答案)
- 天津市紅橋區(qū)2022-2023學年九年級上學期期末英語試題(解析版)
- 《故都的秋》《荷塘月色》聯(lián)讀課件統(tǒng)編版高中語文必修上冊
- 國內(nèi)油氣儲運工程概論
- 全國養(yǎng)老護理職業(yè)技能大賽(養(yǎng)老護理員賽項)試題庫大全-下(判斷題匯總)
評論
0/150
提交評論