/**!
2018年1月30日14:18:00
Author: xiyuan255
Purpose: c語言基礎
*/
/**(1) 函數類型強制轉換示例代碼***start***/
void SelectMainFrame( char tmf )
{
assert( (tmf==0x01) || (tmf==0x02) );
if (0x01 == tmf) {
// execute to AfMain1 frame
} else if (0x02 == tmf) {
// execute to AfMain2 frame
}
}
void AfMain( void( *MainFrameFunc )(void) )
{
char tmf = 0x01;
if ( MainFrameFunc != NULL ) {
/* 該語句的含義是將MainFrameFunc函數強制轉換爲返回值爲void
* 形參爲char型的函數,然後將tmf作爲它的實參,傳遞給該函數 */
( (void ( * )(char) )MainFrameFunc )( tmf );
}
}
int main( void )
{
/* (void( * )(void)) SelectMainFrame 的含義是將SelectMainFrame
* 函數的類型轉換爲返回值爲void,形參爲void的類型,然後作爲實參
* 傳遞給AfMain函數 */
AfMain( (void( * )(void))SelectMainFrame );
/* 同理,該語句同上, 其中pNode是一個鏈表節點指針而已 */
(( void( * )(int*, int) )pNode->function)(buffer, length);
return 0;
}
/**(1) 函數類型強制轉換示例代碼***end***/
/**(2) 指針與變量的解析***start***/
typedef void (*fun3)(int a, int b);
void fun2(int a, int b);
int main(void)
{
while(1) {
int i = 0; // 在c語言中定義變量i並賦值,其實等價與彙編中的直接尋址;
int* p = NULL; // 在c語言中定義指針變量p,其實等價與彙編中的間接尋址;
/* 解釋: 當我們定義一個指針變量p和變量i時,其實是向操作系統申請兩塊內存單元來使用,
即我們能夠對所申請的內存單元進行讀寫使用。一塊內存單元的別名叫做i,一塊內存單元
的別名叫做p。而i所代表的內存單元裏面存放的是數據,且是int類型的數據。而p所代表的
內存單元裏面存放的是地址,且是int類型數據的地址。 */
fun3 q = fun2;
/** 解釋:typedef void (*fun3)(int a, int b);的含義是:定義的一種類型,叫做fun3類型,
該類型是void X(int a, int b)這種類型函數的指針。即用fun3定義的變量q存放的是這種
void fun2(int a, int b)函數的地址。 */
}
return 0;
}
/**
C語言中的變量分爲指針變量和常規變量,它其實等價於內存中的某一塊存儲單元:
(1) 指針變量,通常我們簡稱爲指針。它與常規變量最大的不同點在於,它所代表的內存單元
存放的是地址類型,即void*類型(由於void*可以接收所以類型的指針,所以這裏用它代表
所有的指針類型)。它的存在可以實現彙編中的間接尋址功能。
(2) 常規變量,通常我們簡稱爲變量。它所代表的內存單元存放的是數據類型,即int、char和
short等類型。它的存在可以實現彙編中的直接尋址功能。
總結: 我們的所有面向對象或面向過程的語言,主要研究的就是對內存的使用,即物理內存條;
當我們定義一個變量i,其實是向操作系統申請一塊內存單元來使用,即我們能夠對所申請的
內存單元進行讀寫使用;而該內存單元所對應的首地址就是變量i,即該首地址的另外一個名
稱叫做i(原因程序員不可能記住每個物理的具體地址,而且操作系統不允許軟件直接對硬件
操作,內存分配統一由操作系統管轄);
(3) 函數指針的說明:C語言函數指針與此類似,函數名即變量名,當我們完成一個一個函數的
定義,該函數的方法就將在內存中的某塊區域存放,該區域的地址用函數名錶示。
而 int(*fun)( ) —— fun是一個指針,它指向一個沒有形式參數的函數,這函數返回一個int值.
int* fun()——fun是個函數,它沒有形式參數,返回一個int *型指針。
*/
/**(2) 指針與變量的解析***end***/
/**(3) 字節對齊的示例***start***/
/**
字節對齊的注意點:在32位操作系統上,默認是按4 bytes對齊。
* (1) 基本類型對齊,即char按一個字節對齊,short按兩個字節對齊,int按4個,float按4個和
double按8個。所爲的對齊就是存放的地址能被類似所佔的字節數整除。
* (2) 結構體類型對齊,是按結構體成員中佔最大字節數的那個成員的字節數來對齊的。
*/
typedef struct {
/* 枚舉類型按int類型來存放,即4 bytes */
NetvoxAfReportingDirection_e direction; // 0000H~0003H 4 BYTES
char endpoint; // 0004H 1 BYTES
// 0005H // 補零
unsigned short clusterId; // 0006H~0007H 2 BYTES
unsigned short attributeId; // 0008H~0009H 2 BYTES
char mask; // 000AH 1 BYTES
// 000BH // 補零
unsigned short manufacturerCode; // 000CH~000DH 2 BYTES
union { // reported和received是共用體data的兩個成員,共用體取成
// 員所佔字節總數最大的作爲共用體data所佔的字節數即本例
// 中 reported:8 bytes > received:6 bytes 取8個字節。
// 且對結構體/共用體拆分,則該結構體的中佔字節數最多的是
// reportableChange:4 bytes。所以對齊data需從:0010H~0017H。
// 其中000EH~000FH都補零原因在於000EH~000FH不能被4整除,
// 0010H可以被4整除,所以從該地址開始存放。
struct {
unsigned short minInterval; // 2 BYTES
unsigned short maxInterval; // 2 BYTES // 共8個字節,8能被結構體reported(4bytes:最大字節數)整除,
unsigned int reportableChange; // 4 BYTES // 所以結構體對齊後就是8個字節
} reported;
struct {
unsigned short source; // 2 BYTES
char endpoint; // 1 BYTES // 共5個字節,5不能被結構體received(2bytes:最大字節數)整除,
unsigned short timeout; // 2 BYTES // 所以補一個字節,即結構體對齊後是6個字節
} received;
} data;
} NetvoxAfReportingEntry_t; // 0017H-0000H+1 = 24byte 因24byte可以被最大成員4byte對齊,所以不需要給結構體
// 對齊補零,所以24byes即爲最終所佔的字節數
cout << "\nsizeof(NetvoxAfReportingEntry_t): " << sizeof(NetvoxAfReportingEntry_t) << endl; // 24 bytes