好东西PICC——C语言的点滴
本文关键词:C语言点滴,由笔耕文化传播整理发布。
语言的点滴( C 语言的点滴(转) 由于 icd2 是在线仿真所以回占用部分芯片资源,但连接器并不知道什么地址已经被 icd2 占用,如 果碰巧分配了被 icd2 占用的资源, 回浪费大家的调试时间, 那么如何让连接器知道什么地址不能分配呢? 请参考以下方法
适用条件:在 mplab ide 环境集成 c 编译器 + icd2 调试程序 1.使用 hitec
h c + icd2 选择 compile for icd project->build options->project->picc global
以下这段话表达的意思也不很贴切: 光在中断入口和出口处为了保护和恢复这些中间临时变量就需要大量的开销,严重影响中断服务的效 率。其实,在 picc 中,对中断中使用的临时变量,为了防止重入或覆盖,干脆就是中断专用 在我们的 中断专用。 中断专用 picc 编程中,临时变量(或者说局部变量),都有其生存期,在生存期结束后,可被覆盖。 但中断函数中使用到的临时变量却与一般概念上的临时变量有很大的区别。中断函数中使用到的临时 变量和中断函数中不使用到的临时变量不能占用同一地址。换言之,中断和非中断的临时变量地址不得重 叠。 看一下下面的例程:(16f877a) #include "pic.h" unsigned char i,j,k; void fn1(void) { unsigned char s1[40]; s1[0]=1; }
void interrupt sample (void) { unsigned char s2[50]; s2[0]=1; fn1(); } void main(void) { }
1
说明:i,j,k-----三个全局变量 s1[40]----40 个中断调用使用的临时变量 s2[50]----50 个中断中使用的临时变量 保护 w、status 和 pclath 用去三个内存变量
从上面程序中可以看出,bank0 资源已经耗尽。50+40+3+3=96。由于中断使用了 93 个 ram,这样中断以外 就没有可以使用的临时变量了。也就是说中断使用的临时变量将不会被重入。
再看一下下面的例子: #include "pic.h" unsigned char i,j,k; void fn1(void) { unsigned char s1[20]; s1[0]=1; } void fn2(void) { unsigned char s3[20]; s3[0]=1; } void interrupt sample (void) { unsigned char s2[50]; s2[0]=1; fn1(); } void main(void) { fn2(); } 说明:i,j,k-----三个全局变量 s1[20]----20 个中断调用使用的临时变量 s2[50]----50 个中断中使用的临时变量 s3[20]----20 个非中断使用的临时变量 保护 w、status 和 pclath 用去三个内存变量
2
从上面的例子中也可以看出,中断使用的临时变量和中断外使用的临时变量不可重叠。 eyuge2 兄所说的 picc 自动保护现场,其实就是 picc 对中断中使用的临时变量实施“禁入”。也就是, 中断内可实施中断内临时变量覆盖;中断外的临时变量也可进行覆盖;但中断内外之间的临时变量不可相 互覆盖。 当然为了防止重入,中断中使用的函数不可在中断外被调用。(picc 可自动实施重入检查。) 大家来看一下具体的例子,用 pic16f887a 编译下列程序。
第一次,中断处理函数什么也不做。 #include "pic.h" unsigned int m,n; unsigned char i,j,k,l; void interrupt sample (void) { } void main(void) { } 因为不进行操作,中断函数不需要进行现场保护,编译后结果是直接返回。 0004 0009 retfie
第二次, 中断处理函数增加一条对全局变量的操作。 void interrupt sample (void) { i++; } 编译结果是: 0004 00f0 0005 0803 0006 0183 0007 00a8 0008 0183 0009 0aa0 000a 0828 000b 0083 000c 0ef0 000d 0e70 000e 0009 movwf movf clrf movwf clrf incf movf movwf swapf swapf retfie
3
saved_w 3,w 3 saved_status 3 _i saved_status,w 3 saved_w saved_w,w
从结果看,只保护 w 和 status,不对全局变量进行现场保护。
最后来看一个中断处理函数中调用一个函数 fn()的例子。 在 fn()函数中涉及全局变量和局部变量。 void fn(void) { char temp; temp=i+j; i=temp++; } void interrupt sample (void) { fn(); } 0004 0004 00f0 0005 0803 0006 0183 0007 00a9 0008 080a 0009 00aa 000a 018a 000b 120a 000c 118a 000d 27f9 000e 120a 000f 118a 0010 082a 0011 008a 0012 0012 0829 0013 0083 0014 0ef0 0015 0e70 0016 0009 isr int_entry movwf movf clrf movwf movf movwf clrf bcf bcf call bcf bcf movf movwf int_restore movf movwf swapf swapf retfie
4
saved_w 3,w 3 saved_status 10,w saved_pclath 10 pclath,0x4 pclath,0x3 fn pclath,0x4 pclath,0x3 saved_pclath,w 10
saved_status,w 3 saved_w saved_w,w
在第三个例子中,由于涉及到跨页的问题,中断函数为了能正确返回中断发生处地址,对 pclath 进 行保护。 从以上我们可以看出,无论是在中断处理中使用的变量,还是在中断处理中调用其它函数而使用的变 量,中断函数都不会对其实行自动保护。 当然中断前的地址入栈是属于硬件功能,不需要软件中作出相 应操作。
picc 与指针 1:指针四要素(这部分主要从网上搜索到的,还不错): 指针的类型 指针所指向的类型 指针的值或者叫指针所指向的内存区 指针本身所占据的内存区 指针的类型。 1 指针的类型。 从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针 本身所具有的类型。让我们看看例一中各个指针的类型: (1)int *ptr; //指针的类型是 int * (2)char *ptr; //指针的类型是 char * (3)int **ptr; //指针的类型是 int ** (4)int (*ptr)[3]; //指针的类型是 int(*)[3] (5)int *(*ptr)[4]; //指针的类型是 int *(*)[4] 怎么样?找出指针的类型的方法是不是很简单? 指针所指向的类型。 1 .2 指针所指向的类型。 当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内 容当做什么来看待。 从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符 *去掉, 剩下的就是指针所指向的类型。例如: (1)int *ptr; //指针所指向的类型是 int (2)char *ptr; //指针所指向的的类型是 char (3)int **ptr; //指针所指向的的类型是 int * (4)int (*ptr)[3]; //指针所指向的的类型是 int()[3] (5)int *(*ptr)[4]; //指针所指向的的类型是 int *()[4] 在指针的算术运算中,指针所指向的类型有很大的作用。指针的类型(即指针本身的类型)和指针所 指向的类型是两个概念。当你对 c 越 来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分 成"指针的 类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。 指针的值,或者叫指针所指向的内存区或地址。 1.3 指针的值,或者叫指针所指向的内存区或地址。 指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是 一个一般的数值。在 32 位程序里,所有类型的指针的值都是一个 32 位整数,因为 32 位程序里内存地址全都是 32 位长。 指针所
5
指向的内存区就是从指针的值所代表的那个内存地址开始, 长度为 sizeof(指针所指向的类型)的一片内存 区。以后,我们说一个指针的值是 xx,就相当于说该指针指向了以 xx 为首地址的一片内存区域;我们说 一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址指针所指向的内存区和指 针所指向的类型是两个完全不同的概念。在例一中 ,指针所指向的类型已经有了,但由于指针还未初始 化,所以它所指向的内存区 是不存在的,或者说是无意义的。 以后,每遇到一个指针,都应该问问:这 个指针的类型是什么?指针指向的 类型是什么?该指针指向了哪里? 1.4 指针本身所占据的内存区。 指针本身所占据的内存区。 指针本身占了多大的内存?你只要用函数 sizeof(指针的类型)测一下就知道了。在 32 位平台里,指针 本身占据了 4 个字节的长度。 指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。 (注释:在 picc18 里,指针占用了两个字节) int data[10]={1,2,4,5,6,7,8}; int lenth1,lenth2,lenth3; int *ptr1,*ptr2; main() { ptr1=&data[0]; ptr2=&data[1]; lenth1=ptr2-ptr1; lenth2=(int)ptr2-(int)ptr1; lenth3=*ptr2-*ptr1; } 在 watch 窗口可以看到 lenth1 为 1,而 lenth2 为 2,可以这样解释:在 lenth1=ptr2-ptr1;这条语句中 两个 int 类型指针变量相减得一个(这在 c 中是允许的)非指针的数,这个数的代表如下: 如果这两个指针指向的内型为 int 型,那么这个数代表两个指针之间相隔多少个 int 型变量,显然在以上 程序中,data[0],和 data[1]之间相隔了 1 个 int 型变量而在 lenth2=(int)ptr2-(int)ptr1;实际上是求 data[1]和 data[0]之间占用多少个内存空间,注意(int)ptr 是 ptr 的值(不是 ptr 所指向的数的值) lenth3=*ptr2-*ptr1;相信稍微懂 c 的人都知道是在求 ptr 所指向的两个值之间的差,和 lenth3=data[1]-data[0]等效大家不防试试 lenth4=(char*)ptr2-(char*)ptr1;看看等于多少, 2: 指针函数和函数指针有什么区别 2.1,这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。我们知道函数都又返 回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。其定义格式如下所 示: 返回类型标识符 *返回名称(形式参数表) { 函数体 } 返回类型可以是任何基本类型和复合类型。返回指针的函数的用途十分广泛。事实上,每一个函 数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。比如函数
6
下面就 picc18 列举个实例看下面程序
返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函 数相当于一个“变量”。例如下面一个返回指针函数的例子: char data[10];
char* test(void); main() { char *ptr; ptr=test(); } char* test(void) { char *p; p=data; return p; } 注意:该程序在 picc18 中调试 2.2,“函数指针”是指向函数的指针变量,因而“函数指针”本身首先应是指针变量,只不过该指针变量 指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,c 在编 译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量 后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。函数 指针有两个用途:调用函数和做函数的参数。函数指针的说明方法为: 数据类型标志符 (*指针变量名)(参数);注:函数括号中的参数可有可无,视情况而定。 下面的程序说明了函数指针调用函数的方法: char max(char x,char y); char min(char x,char y); char (*ptr)(char,char); char a=2,b=3,c; main() { ptr=max; c=(*ptr)(a,b); ptr=min; c=(*ptr)(a,b); } char max(char x,char y) {
7
return x>=y?x:y; } char min(char x,char y) { return x<=y?x:y; } 注意:该程序在 picc18 中调试 在 pic 的 c 程序编写中,函数指针不是很常用,如果大家有兴趣看看 ucos 的 pic18 的移植版本,就可以 发现 ucos 中是用函数指针传递任务程序的入口地址的。
3:结构联合与指针 先看下面的一个简单的举例 typedef struct datas { char datah; char datal; struct datas *next; } data; //a 是一个结构变量 data a,b; data *ptr1,*ptr2; main() { ptr1=&a; ptr1->datah =1; ptr1->datal =2; ptr2=&b; ptr1->datah =3; ptr1->datal =4; ptr1->next=ptr2; ptr2->next=0; } 数据 a,b 是一个结构型变量,ptr 则是指向结构型变量的指针,在 c 语言里,通过形如 ptr->x 的形式来 访问结构或者指针的成员。在结构变量中定义了一个指针 struct datas *next; 这是在指针链中常用到 的,ptr1->next=ptr2; ptr2->next=0;实际上已经建立了一条简单的指针链,当然建立指针链用这种初始 化的方法不够简单,但是上面的程序只是为了说明指针和结构而已。
8
在单片机的 c 语言程序中,联合和结构是经常用在一起的下面在举一个简单的列子: typedef struct { char datah; char datal;
} data; typedef union { data int twpbyte; bytes;
} piccdata; piccdata adres[10]; piccdata *ptr1,*ptr2; char lenth1,lenth2; main() { ptr2=adres; ptr1=adres; ptr1++; lenth1=ptr1-ptr2; lenth2=(char)ptr1-(char)ptr2;
} 在以上程序中,lenth2 为 2,而 lenth1 为 1,道理和第一个列子一样,只是应该注意的是在 piccdata 型 变量中占用的空间为 2 个字节而不是 4 个字节!!! 另:结构与联合是 pic 应用的一个好东西,这点 hotpower 曾经有一很经典的文章,在此列中,只要稍微 加以改动,就可以对一个 16 位变量即可以整体访问,也可分为高八位访问和低八位访问。这在 ad 转换中 是很有用的。 4: const 与指针 如果 const 关键字不涉及到指针,我
const 是一个 c 语言的关键字,它限定一个变量不允许被改变。 们很好理解,下面是涉及到指针的情况: int b = 500; const int* a = &b; int const *a = &b; int* const a = &b; [1] [2] [3]
9
const int* const a = &b;
[4]
如果 const 位于星号的左侧,则 const 就是用来修饰指针所指向的变量,即指针指向为常量;如果 const 位于星号的右侧,const 就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针 所指向的内容为常量(const 放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如 不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更 改操作,如 a++是错误的;[4]为指针本身和指向的内容均为常量。有了上面的基础,对于在 picc18 中的 c 语言应用就可以开始了,在单片机编程中,经常会用到查表程序等,通常把大量的数据放入 rom 中,下 面是一个简单的列子
const int a[8]={1,2,3,-3,3,5,6,7}; const int *ptr; main() { ptr=a; ptr++; } 显然 ptr 是一个指向常量的指针,ptr 指向的数是不可变的,,但是 ptr 本身是可变的,我们可以通过 ptr 来访问定义在 rom 中的数组 a[8]; 欢迎补充和指正,谢谢! 读写片内 eeprom 数据区,每一本相关的数据手册都有详细的例程,抄上去就可以了。如果连抄上也不行, 那你还有什么是可以的呢? 什么都想要现成的,自己一点主观的进取心都没有。你要用 c 写程序,这当然是好事,可是连现成的汇编 语句都无法用 c 语言复述一遍,那你还能用 c 写出什么有用的代码? 自己如果不清楚,就不要瞎说。什么“不是将 wr 置 1,写完后会自动将 wr 置 1”:事实正好相反。 可能又要说是初学之类的借口了。那反问一句:这象认真学习的模样吗? 算了,附上一些代码吧,仅供参考。 //============================================================= //write a byte of data into eeprom memory //input: // // eedata - data to be written eeaddr - eeprom memory address
//return: // // // 0 - successful 1 - data error 2 - time out
10
//=============================================================
unsigned char ee_write(void) { unsigned char tmpdata; eeif = 0; eedata = eedata; eeadr = eeaddr; eepgd = 0; wren gie = 1; = 0; //data to write //adress to write //point to ee area //ee write enabled //no interrupt following //password 55 //password aa //internal ee write cycle begin now //ee write can be disabled //interrupt could be enabled //for backgound time-out control
eecon2 = 0x55; eecon2 = 0xaa; wr wren gie = 1; = 0; = 1;
timer = 10; do {
asm("clrwdt"); } while (eeif==0 && timer!=0); //wait for ee write completed or time-out if (eeif==1 && timer!=0) { tmpdata = eedata; ee_read(); //read back the written data //verify //ee write completed normally
if (tmpdata == eedata) return(0); else return(1); } else return(2); }
//data is good
//data is corrupted
//ww write time out
//============================================================= //read a byte of data from eeprom memory //input: // eeaddr - eeprom memory address
//output // eedata - data read
//============================================================= void ee_read(void)
11
{ eedata = 0xff; eeadr = eeaddr; eepgd = 0; rd = 1;
eedata = eedata; }
12
深入理解 C 语言指针的奥秘 指针的概念 例三:
intarray[20]; int*ptr=array; ... //此处略去为整型数组赋值的代码。 ... for(i=0;ia; ptr->b; ptr->c;
又请问怎样通过指针 pstr 来访问 ss 的三个成员变量? 答案: *pstr;//访问了 ss 的成员 a。 *(pstr+1);//访问了 ss 的成员 b。 *(pstr+2)//访问了 ss 的成员 c。 虽然我在我的 MSVC++6.0 上调式过上述代码,但是要知道,这样使用 pstr 来访问结构成员是不正规的,为了说明为什么不正规,让我们看看怎样通过指针来访问数组的各个单元: 例十二:
intarray[3]={35,56,37}; int*pa=array; 通过指针 pa 访问数组 array 的三个单元的方法是: *pa;//访问了第 0 号单元 *(pa+1);//访问了第 1 号单元 *(pa+2);//访问了第 2 号单元 从格式上看倒是与通过指针访问结构成员的不正规方法的格式一样。 所有的 C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。但在存放结构对象的各个成员时,在某种编译环境下,可能会 需要字对齐或双字对齐或者是别的什么对齐,需要在相邻两个成员之间加若干个"填充字节",这就导致各个成员之间可能会有若干个字节的空隙。
所以,在例十二中,即使*pstr 访问到了结构对象 ss 的第一个成员变量 a,也不能保证*(pstr+1)就一定能访问到结构成员 b。因为成员 a 和成员 b 之间可能会有若干填充字节,说不 定*(pstr+1)就正好访问到了这些填充字节呢。这也证明了指针的灵活性。要是你的目的就是想看看各个结构成员之间到底有没有填充字节,嘿,这倒是个不错的方法。 通过指针访问结构成员的正确方法应该是象例十二中使用指针 ptr 的方法。 指针和函数的关系 可以把一个指针声明成为一个指向函数的指针。
intfun1(char*,int); int(*pfun1)(char*,int);
13
pfun1=fun1; .... .... inta=(*pfun1)("abcdefg",7);//通过函数指针调用函数。 例十三: 可以把指针作为函数的形参。在函数调用语句中,可以用指针表达式来作为实参。
intfun(char*); inta; charstr[]="abcdefghijklmn"; a=fun(str); ... ... intfun(char*s) { intnum=0; for(inti=0;i{ num+=*s;s++; } returnnum; } 这个例子中的函数 fun 统计一个字符串中各个字符的 ASCII 码值之和。前面说了,数组的名字也是一个指针。在函数调用中,当把 str 作为实参传递给形参 s 后,实际是把 str 的值 传递给了 s,s 所指向的地址就和 str 所指向的地址一致,但是 str 和 s 各自占用各自的存储空间。在函数体内对 s 进行自加 1 运算,并不意味着同时对 str 进行了自加 1 运算。 指针类型转换 当我们初始化一个指针或给一个指针赋值时,赋值号的左边是一个指针,赋值号的右边是一个指针表达式。在我们前面所举的例子中,绝大多数情况下,指针的类型和指针表达式 的类型是一样的,指针所指向的类型和指针表达式所指向的类型是一样的。 例十四: 1、floatf=12.3; 2、float*fptr=&f; 3、int*p; 在上面的例子中,假如我们想让指针 p 指向实数 f,应该怎么搞?是用下面的语句吗? p=&f; 不对。因为指针 p 的类型是 int*,它指向的类型是 int。表达式&f 的结果是一个指针,指针的类型是 float*,它指向的类型是 float。两者不一致,直接赋值的方法是不行的。至少在 我的 MSVC++6.0 上,对指针的赋值语句要求赋值号两边的类型一致,所指向的类型也一致,其它的编译器上我没试过,大家可以试试。为了实现我们的目的,需要进行"强制类型转换": p=(int*)&f; 如果有一个指针 p,我们需要把它的类型和所指向的类型改为 TYEP*TYPE, 那么语法格式是: (TYPE*)p; 没有被修改。 这样强制类型转换的结果是一个新指针,该新指针的类型是 TYPE*,它指向的类型是 TYPE,它指向的地址就是原指针指向的地址。而原来的指针 p 的一切属性都
14
一个函数如果使用了指针作为形参,那么在函数调用语句的实参和形参的结合过程中,也会发生指针类型的转换。 例十五:
voidfun(char*); inta=125,b; fun((char*)&a); ... ... voidfun(char*s) { charc; c=*(s+3);*(s+3)=*(s+0);*(s+0)=c; c=*(s+2);*(s+2)=*(s+1);*(s+1)=c; } } 注意这是一个 32 位程序,故 int 类型占了四个字节,char 类型占一个字节。函数 fun 的作用是把一个整数的四个字节的顺序来个颠倒。注意到了吗?在函数调用语句中,实参&a 的结果是一个指针,它的类型是 int*,它指向的类型是 int。形参这个指针的类型是 char*,它指向的类型是 char。这样,在实参和形参的结合过程中,我们必须进行一次从 int*类型到 c har*类型的转换。结合这个例子,我们可以这样来想象编译器进行转换的过程:编译器先构造一个临时指针 char*temp, 然后执行 temp=(char*)&a,最后再把 temp 的值传递给 s。所 以最后的结果是:s 的类型是 char*,它指向的类型是 char,它指向的地址就是 a 的首地址。 我们已经知道,指针的值就是指针指向的地址,在 32 位程序中,指针的值其实是一个 32 位整数。那可不可以把一个整数当作指针的值直接赋给指针呢?就象下面的语句: unsignedinta; TYPE*ptr;//TYPE 是 int,char 或结构类型等等类型。 ... ... a=20345686; ptr=20345686;//我们的目的是要使指针 ptr 指向地址 20345686(十进制 ) ptr=a;//我们的目的是要使指针 ptr 指向地址 20345686(十进制) 编译一下吧。结果发现后面两条语句全是错的。那么我们的目的就不能达到了吗?不,还有办法:
unsignedinta; TYPE*ptr;//TYPE 是 int,char 或结构类型等等类型。 ... ... a=某个数,这个数必须代表一个合法的地址; ptr=(TYPE*)a;//呵呵,这就可以了。 严格说来这里的(TYPE*)和指针类型转换中的(TYPE*)还不一样。这里的(TYPE*)的意思是把无符号整数 a 的值当作一个地址来看待。上面强调了 a 的值必须代表一个合法的地址,否 则的话,在你使用 ptr 的时候,就会出现非法操作错误。
15
想想能不能反过来,把指针指向的地址即指针的值当作一个整数取出来。完 全可以。下面的例子演示了把一个指针的值当作一个整数取出来,然后再把这个整数当作一个地址赋给 一个指针: 例十六:
inta=123,b; int*ptr=&a; char*str; b=(int)ptr;//把指针 ptr 的值当作一个整数取出来。 str=(char*)b;//把这个整数的值当作一个地址赋给指针 str。 现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针。 指针的安全问题 看下面的例子: 例十七:
chars='a'; int*ptr; ptr=(int*)&s; *ptr=1298; 指针 ptr 是一个 int*类型的指针,它指向的类型是 int。它指向的地址就是 s 的首地址。在 32 位程序中,s 占一个字节,int 类型占四个字节。最后一条语句不但改变了 s 所占的一个 字节,还把和 s 相临的高地址方向的三个字节也改变了。这三个字节是干什么的?只有编译程序知道,而写程序的人是不太可能知道的。也许这三个字节里存储了非常重要的数据,也 许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,这三个字节的值被改变了!这会造成崩溃性的错误。 让我们再来看一例: 例十八: 1、chara; 2、int*ptr=&a; ... ... 3、ptr++; 4、*ptr=115; 该例子完全可以通过编译,并能执行。但是看到没有?第 3 句对指针 ptr 进行自加 1 运算后,ptr 指向了和整形变量 a 相邻的高地址方向的一块存储区。这块存储区里是什么?我们 不知道。有可能它是一个非常重要的数据,甚至可能是一条代码。而第 4 句竟然往这片存储区里写入一个数据!这是严重的错误。所以在使用指针时,程序员心里必须非常清楚:我的 指针究竟指向了哪里。在用指针访问数组的时候,也要注意不要超出数组的低端和高端界限,否则也会造成类似的错误。 在指针的强制类型转换:ptr1=(TYPE*)ptr2 中,如果 sizeof(ptr2 的类型)大于 sizeof(ptr1 的类型),那么在使用指针 ptr1 来访问 ptr2 所指向的存储区时是安全的。如果 sizeof(ptr2 的类型)小于 sizeof(ptr1 的类型),那么在使用指针 ptr1 来访问 ptr2 所指向的存储区时是不安全的。至于为什么,读者结合例十七来想一想,应该会明白的。
16
更多相关文档:
C语言点滴.
表达式运算的顺序是由平台和编译器决定的,凡是涉及某个值得表达式,最好可以 自...PICC——C语言的点滴 16页 1下载券 C语言教程(最全配套免费... 533页 5...
PICC入门笔记
PICC 入门笔记 PIC 单片机 C 语言编程入门笔记 一、 C 语言基础复习---没 C 语言基础看起来可能有点困难。C程序的语句 语句名称 表达式语句 函数调用语句 控制...
PIC单片机的C语言使用
语言使用( PIC 单片机的 C 语言使用(一) 在 MPLAB-IDE 中使用 HitechC 编译...5、节点文件的工具这时应该选择为“PICC Compiler”(C 编译器),蓝色圈子里的 ...
第7章 秒表
PICC-C语言实例PICC-C语言实例隐藏>> 第7章 秒表 最小巧、最精致、测试最完整、性价比最高的无线射频开发平台和模块: NORDIC 无线射频开发平台系列 NORDIC 无线射...
更多相关标签:
c语言点滴 | c语言点滴 赵岩 pdf | c语言点滴 pdf | c语言点滴 百度网盘 | c语言点滴 pdf下载 | C语言点滴pdf百度云 | 英壮英达都不是好东西 | 脑子是个好东西 |本文关键词:C语言点滴,由笔耕文化传播整理发布。
本文编号:247393
本文链接:https://www.wllwen.com/wenshubaike/mishujinen/247393.html