///指针访问内存
1、内存地址理解
{
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
}
请问p1+5=? ;
p2+5=? ;
答:p1+5=0x801005 ;
p2+5=0x810014 ;
在32位系统中,字节数为4字节;在64位系统中,Visual C++和Mingw64 unsigned long字节数为4字节。GCC(POSIX系统以及Cygwin)为8字节,Clang的与GCC类似,不同平台不同实现。
2、访问固定的内存位置
要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器,写代码去完成这一任务。
答:访问一个绝对地址,必须把整型的地址转化为可写的指针。
{
int *ptr;
ptr = (unsigned int *)0x67a9;
*ptr = 0xaa66;
// 或者
// *(unsigned int*)0x67a9 = 0xaa66;
}
///函数指针
函数指变使用:
定义:void (*p)(); 赋值:p=fun; 调用:(*p)();
1、让程序跳转到绝对地址是0x100000去执行,应该怎么做?
答:*((void (*)())0x100000 ) ( );
首先要将0x100000 强制转换成函数指针,即: (void (*)())0x100000 然后再调用它: *((void (*)())0x100000)();
用typedef可以看得更直观些: typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
2、计算机启动时,硬件调用首地址为0位置的子例程(0地址存main函数指针,如何调用):
(*(void(*)())0)();
详细解析:
====声明变量和函数
【1】 float *pf; 一个指向浮点数的指针。
【2】 float f(); 一个返回值为浮点类型的函数。
【3】 float *g(); ()结合性优先级高于* ; 声明g(指针)函数,函数返回的是一个 指向浮点数的指针。
【4】 float (*h)(); 声明 指针h,h是一个函数指针,其指向的函数的返回值为浮点类型。
@区别3和4; void *pFun(); 和 void (*pFun)();
====类型转换符
由声明知道该类型的类型转换符: 声明中的变量名和分号去掉,剩余的部分用括号 封装起来。
(float(* )()) :表示一个 "指向返回值为浮点类型的函数的指针" 的类型转换符 。
===== 调用:
首先必须给指针赋值,然后就是给指针带上括号,如果有参数的话,带上实参。
用函数指针来 调用函数: (* fp)();
fp为函数指针,*fp就表示指针指向的函数名,(* fp)()为调用方式。小心写成* fp();
===== 引入:
(*0)(); 调用0地址存储的函数。
0必须为 指针,而且是函数指针,必须类型转换。转换后为: 指向返回值为void类型的函数的指针。
void (* fp)();
fp = 0;
(* fp)();
(void (*)())0; //对常数进行类型转换,将其转换成为该变量的类型.
(*(void(*)())0)(); //然后用转换后的0来替代fp:
====简化:
对复杂变量建立一个类型别名的方法很简单,只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
typedef void(* funcptr)();
(*(funcptr)0) ( );
///typedef
1、定义:typedef 为现有类型创建一个新的名字,或称为类型别名。并不创建新的类型。它仅仅为现有类型添加一个同义字。
例如: typedef int size; 此声明定义了一个int的同义字,名字为size。
2、原因:有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法 。有助于编写出更加美观和可读的代码,增强可移植性以及未来的可维护性。
3、格式: 新类型出现在所声明的变量名字中,位于“typedef”关键字右边。
【1】
char text[81];
typedef char Line[81]; // 此时Line类型即代表了具有81个元素的字符数组
Line text;
getline(text);
【2】
typedef char * pstr;
typedef const char* pCstr;
int mystrcmp(pstr, pCstr);