/**!
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