|
技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | EMC技术 | ARM技术 | EDA技术 | PCB技术 | 嵌入式系统 驱动编程 | 集成电路 | 器件替换 | 模拟技术 | 新手园地 | 单 片 机 | DSP技术 | MCU技术 | IC 设计 | IC 产业 | CAN-bus/DeviceNe |
高手都会搞错的问题,大家来讨论! |
作者:xwj 栏目:单片机 |
C语言指针的一个问题: 如果已经完成了指针变量的定义和应用, int *p; int a[10]; p=a; 则在进行指针运算时,这个语句的具体行为和结果 *p++=n; 是 1、a[0]=n,再p++; 还是 2、p++,a[1]=n; 还是其他? C语言指针的一个问题,书上说法全都自相矛盾 大家想清楚再回答 |
2楼: | >>参与讨论 |
作者: 艾森豪威尔 于 2005/7/13 11:10:00 发布:
难道不是先a[0]=n,再p++吗? |
3楼: | >>参与讨论 |
作者: lczsx2000 于 2005/7/13 11:23:00 发布:
*p = n; p++; |
4楼: | >>参与讨论 |
作者: AVRx007 于 2005/7/13 11:31:00 发布:
后加。 不应该搞错的。 |
5楼: | >>参与讨论 |
作者: IceAge 于 2005/7/13 11:40:00 发布:
想问一下, 是 那本书上说是p++,a[1]=n; ? |
6楼: | >>参与讨论 |
作者: xwj 于 2005/7/13 12:00:00 发布:
写书的作者自己都没搞懂就乱说一气 天下文章一大抄,错都错得一模一样,真是让人气愤! 大家把自己的书看看,估计很多书都有这样的话; “*p++,由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++). 作用是先得到P指向的变量的值(即*P),然后再使P+1->” [ff0000]这前面一句真是放P,竟然说*p++等价于*(p++)!后面倒是对的[/#] “如果已经完成了指针变量的定义和应用, int *ap; int a; ap=&a; 则再进行指针运算时, 1、*ap与a时等价的,即*ap就是啊a 2、&*ap:由于*ap与a 等价,则&*ap与&a等价 3、*&a:由于ap与&a等价,则*&a与*ap等价,即*&a 与a 等价 4、*ap++相当于a++” 我也是认为, *p++ 是取数后指针再加,也就是1、a[0]=n,再p++; |
7楼: | >>参与讨论 |
作者: AVRx007 于 2005/7/13 12:09:00 发布:
尽信书不如无书。 以前的高手写书还有点道德。 现在,一切向"钱"看. 网络上更多谣传的,很多网站,转载别人的也不考究一下,而且脸皮特厚,还老说是自己写的。 |
8楼: | >>参与讨论 |
作者: 艾森豪威尔 于 2005/7/13 12:11:00 发布:
哪本数?书名是什么? |
9楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/13 12:30:00 发布:
别再深究了,估计是原贴写错了 把(*p)++写错为*(p++),估计不是书的错,因为后面的话是对的。 |
10楼: | >>参与讨论 |
作者: wy051 于 2005/7/13 13:32:00 发布:
楼主真的开贴讨论了!!!!!! 为了更好的搞清楚这个*P++与*(P++)的问题,我决定用Keil C 汇编器试一试,运行后的汇编结果如下: *P++=11; ; SOURCE LINE # 6 MOV R3,P?041 INC P?041+02H MOV A,P?041+02H MOV R2,P?041+01H JNZ ?C0002 INC P?041+01H ?C0002: DEC A MOV R1,A MOV A,#0BH LCALL ?C?CSTPTR ; *(P++)=22; ; SOURCE LINE # 7 MOV R3,P?041 INC P?041+02H MOV A,P?041+02H MOV R2,P?041+01H JNZ ?C0003 INC P?041+01H ?C0003: DEC A MOV R1,A MOV A,#016H LCALL ?C?CSTPTR OK,农民老兄,现在你不承认都不行,*P++与*(P++)的确是一回事,不信你也可以用Keil C试试.当然后面一种写法的确不是很好的编程风格,既然一样,为什么要多敲两个括号呢?多此一举,以后要改!因为以前经常写51单片机的程序,所以一直求执行速度,有时程序风格不好,所以这么多人误会,以后也要改啊 !当然有一点可以肯定,xwj兄肯定没有上机调试我的程序,其实COPY过去直接在TC2里运行一下什么都知道了!当然最主要的是只看了区部,没看整体,这个程序所有函数没问题! charToStrD(Tnum,Pstr)的返回指针我在主程序没有用到,所以就没关心这个返回值的问题.但StrAddState(Midstrtable,Pbuf,4,ValueEqual)的返回指针用到了,本来刚开始我也没想用这个返回指针,所以Pbuf=StrAddState(Midstrtable,Pbuf,4,ValueEqual);这一句就要写两行代码StrAddState(Midstrtable,Pbuf,4,ValueEqual);Pbuf+=8;最后总觉得不爽,所以----- 至于用C自带函数的问题,我也想过,可就是不理想,故自已写了函数.不过,看了大家的贴后,也暴露了自己的很多问题,程序风格重要啊,记得有一个同事说的很对,程序应该是写给别人看的. |
11楼: | >>参与讨论 |
作者: computer00 于 2005/7/13 14:04:00 发布:
为什么要写这样的代码呢?我就从来不干这种劳命伤财的事 分开两句来写,不是好得很? *p=n; p++; 一看就明白。 |
12楼: | >>参与讨论 |
作者: xwj 于 2005/7/13 14:25:00 发布:
自认高手的先看这个贴,看看自己是否还有不足 |
13楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/13 14:51:00 发布:
还要在这里再说一遍,麻烦 书上对的,*p++ 和 *(p++)结果是一样的。 误导教唆犯,犯罪了。 没用过*(p++),农民见识少点,别丢砖头过来了。 |
14楼: | >>参与讨论 |
作者: liudewei 于 2005/7/13 15:25:00 发布:
本以为++优先级高于* 其实从右至左,看来括号不能轻易省 * - 本贴最后修改时间:2005-7-13 15:51:06 修改者:liudewei |
15楼: | >>参与讨论 |
作者: yewuyi 于 2005/7/13 15:53:00 发布:
忍不住问两句 XWJ的问题,我肯定是选择第一个答案。 首先声明: 我不会用C,只是以前偶尔偷“摸”了两把(呵呵,不会有人说我非礼把)。 在我学习C的过程中,从来都认为*(P++) != *P++ 在KEIL里面为何两种编译结果相同,我是没搞明白?是不是因为历史的缘故? 从ANSI-C语法上分析,两者能等同吗?即使不推荐那种写法,但从C规则来讲,这两种写法是否确实是等同的呢? 还望所长&xwj及其他朋友指教。 |
16楼: | >>参与讨论 |
作者: athlon64fx 于 2005/7/13 16:09:00 发布:
re *p = n; p++; 和 *p++ = n; 编译结果未必一样,虽然运行结果是相同的. *p++ 可能直接使用 CPU 带"后加"的指令. 关于 *p++ 和 *(p++) 这个 too simple,sometimes naive 的问题, 请考虑 p++ 和 ++p. |
17楼: | >>参与讨论 |
作者: AVRx007 于 2005/7/13 19:57:00 发布:
我认为这是编译器的BUG. *p++ 先读/写 后加指针。 *++p 先加指针 后读/写。 *p-- 先读/写 后减指针。 *--p 先减指针 后读/写。 AVR的指令就有后加和预减,以实现高速读写。 LD Rd,X+ ST X+,Rr [*p++] LD Rd,-X ST -X,Rr [*--p] |
18楼: | >>参与讨论 |
作者: hotpower 于 2005/7/13 22:42:00 发布:
1. |
19楼: | >>参与讨论 |
作者: yewuyi 于 2005/7/14 10:28:00 发布:
关于 *p++ 和 *(p++) 这个 too simple,sometimes naive 的问题 simple and naive也不是什么坏事情. 简单的问题对于没有掌握它的人来说就是一个天大的难题…… …… |
20楼: | >>参与讨论 |
作者: xwj 于 2005/7/14 11:05:00 发布:
经测试,*p++ 和 *(p++)是一样的,都是 经测试,*p++ 和 *(p++)是一样的,都是“先得到P指向的变量的值(即*P),然后再使P+1”, 也就是都是1、a[0]=n,再p++; 一直理解x++为执行完当前语句再后加,经测试实际结果与预想的一致。 只是没想到*(p++)的行为也是“先得到P指向的变量的值(即*P),然后再使P+1”, 书上这句话竟然是对的!这个括号还真能捣乱啊 “*p++,由于++和*同优先级,结合方向为自右而左,因此它等价于*(p++). 作用是先得到P指向的变量的值(即*P),然后再使P+1” 当然,下面这段: “如果已经完成了指针变量的定义和应用, int *ap; int a; ap=&a; 则再进行指针运算时, 1、*ap与a时等价的,即*ap就是啊a 2、&*ap:由于*ap与a 等价,则&*ap与&a等价 3、*&a:由于ap与&a等价,则*&a与*ap等价,即*&a 与a 等价 4、*ap++相当于a++” 第四点肯定是错的,估计是“4、(*ap)++相当于a++”的笔误吧 C可以把一大堆东西写在一起,结果理解起来就仁者见仁智者见智了 很明显,这不是好的编程习惯,应该尽量避免 最好还是分开写的好,以避免理解不透彻或可能混淆的情况 附测试程序: #include <REG52.H> #include <stdio.h> #define uLONG unsigned LONG #define uint unsigned int #define uCHAR unsigned CHAR uCHAR buf[20]; uCHAR *p; void main (void) { uCHAR i; SCON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */ TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */ TH1 = 250; /* TH1: reload VALUE for 1200 baud @ 16MHZ */ TR1 = 1; /* TR1: timer 1 run */ TI = 1; /* TI: set TI to send first CHAR of UART */ p=buf; for (i=0;i<10;i++) { *p++ = i+'0'; printf("buf= %s \n",buf); *(p++) = i+'0'; printf("buf= %s \n",buf); } while(1) {;} } 输出结果: buf= 00112233445566778899 * - 本贴最后修改时间:2005-7-15 19:15:37 修改者:xwj |
21楼: | >>参与讨论 |
作者: hiberhe 于 2005/7/15 9:45:00 发布:
应该是1吧.试一下就知道了.不过拒绝写这种代码 现在不爱去想优先级的问题了,不确定,加括号,反正又不会造成不好后果. 花那么多时候去想干嘛(头儿这么教育的:)),又不是在考试... |
22楼: | >>参与讨论 |
作者: mikejx 于 2005/7/15 10:44:00 发布:
现在就连加括号前也要想想有什么后果 c就这些规则太麻烦了 |
23楼: | >>参与讨论 |
作者: xwj 于 2005/7/15 14:41:00 发布:
有时括号也不可靠 这个问题就是由括号带来的, 在别的帖子讨论*p++ 和 *(p++)是不是一样,结果却出乎意料, 估计和很多人猜想的不一样 有些东西没试过还真不好说 |
24楼: | >>参与讨论 |
作者: computer00 于 2005/7/15 17:15:00 发布:
C语言不是规定了吗?对于p++,是先取值,后++ 而括号是并不影响这个操作的。会先用p的值计算,遇到分号后,才会执行++。 所以使用p++时,是相当于把p=p+1;放到了下面一条语句。 你不要认为加了一个括号就会让它先运算了。 后加1操作是对整条语句来说的,跟括号没关系。 |
25楼: | >>参与讨论 |
作者: hotpower 于 2005/7/15 18:39:00 发布:
computer00看的是"水气" P++必须等该语句执行完后下一语句才真正的P++,真与括号无关. 括号也只能负责本条语句,它再大的能耐也管不了下句!!! |
26楼: | >>参与讨论 |
作者: computer00 于 2005/7/15 19:41:00 发布:
"水气",我还"热水器"呢,怎么说也得要跟你这个"热水"扯上点关系 |
27楼: | >>参与讨论 |
作者: liudewei 于 2005/7/16 19:23:00 发布:
是的,这一句括号还不管用,真没有这样用过 |
28楼: | >>参与讨论 |
作者: long8725 于 2005/7/17 18:26:00 发布:
烦,还想误导 |
29楼: | >>参与讨论 |
作者: 边锋 于 2005/7/17 19:27:00 发布:
很简单,防真一下就什么都明白了! 很简单,防真一下就什么都明白了! |
30楼: | >>参与讨论 |
作者: 笨笨兔 于 2005/7/18 0:37:00 发布:
哈哈,同样的话题 嘿嘿,这个问题上周六我也思考过,试图从运算符的结合顺序及其优先级去分析,歪写了一篇: //www.21icbbs.com/club/bbs/ShowAnnounce.asp?v=&ID=1739180 虽然是投机的分析,但对记忆有点帮助呢。 已经建议公司的Coding Rule中增加:除了大家非常清楚的 *p++的写法外,其他包含 ++、--的算式,一律分开写。毕竟产品追求的是可靠性,换个人来,不至于又理解错了。 而且 诸如 TEMP = *p++;的写法,跟 写成 TEMP= *p; p++;编译效率几乎一致,初学者也都看得懂,可是再写成 TEMP = *(p++)的话,相信多数人都会理解错! |
31楼: | >>参与讨论 |
作者: shanyongde 于 2005/7/18 16:28:00 发布:
这是我在tc2.0上试验的结果 #include"stdio.h" int*p, a[3]={1,2,3}; main() { p=a; *p++=16; printf("%d\n",a[1]); printf("%d\n",a[0]); printf("%d\n",*p); } 输出的结果是:2 16 2 可见正确的操作应该是a[0]=16; 然后p++的 |
32楼: | >>参与讨论 |
作者: 波动光学 于 2005/7/18 21:29:00 发布:
a[0]=n,再p++; 先a[0]=n,再p++,p指向a[1]! |
33楼: | >>参与讨论 |
作者: hunter01 于 2005/7/19 9:31:00 发布:
这样写,代码的速度快了吗?劳民伤财, 而且不一定每次用完指针都要加1。把人会搞糊涂的嘿嘿, |
34楼: | >>参与讨论 |
作者: canycao 于 2005/7/19 10:03:00 发布:
看编译器的,不同的编译器出来的结果不同 做过类似的试验,用了TC,VC++...等不同6、7种不同的编译环境,出来的结果是不一样的。 |
35楼: | >>参与讨论 |
作者: xxlale 于 2005/7/19 11:27:00 发布:
IGBT的使用 我想实现单片机输出控制大功率的继电器,除了正反向二极管之外,可不可以使用IGBT,如何实现? |
36楼: | >>参与讨论 |
作者: victorymay 于 2005/7/19 11:40:00 发布:
"++"应先级高于* - |
37楼: | >>参与讨论 |
作者: lhkjg 于 2005/7/19 13:42:00 发布:
就是就是,这样的代码称之为“垃圾代码” |
38楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/19 13:55:00 发布:
*p++可被优化,*p,p++不能。 |
39楼: | >>参与讨论 |
作者: refugee 于 2005/7/19 16:42:00 发布:
++在后,是先操作后在自加1 |
40楼: | >>参与讨论 |
作者: 赤铸 于 2005/7/19 21:11:00 发布:
说白了还是基本概念问题 C语言的一个重要特性就是表达式与执行语句的重叠,一个重要概念就是表达式的“值”(真正理解这个概念的人不多,哪怕是一些资深工程师) 而整体加括号是不影响表达式的值的,所以表达式p++和(p++)的值完全相等,由于++优先级更高,表达式*p++与*(p++)的值也完全相等 |
41楼: | >>参与讨论 |
作者: yadog 于 2005/7/19 21:42:00 发布:
指针 路过 |
42楼: | >>参与讨论 |
作者: elelab 于 2005/7/19 22:35:00 发布:
矛盾,连这个都搞错还是高手啊 |
43楼: | >>参与讨论 |
作者: AVRx007 于 2005/7/19 23:11:00 发布:
在*p++中,明明是*的优先级高于++,怎么还有人乱说什么基本概念? *p++; = *p; p++; *p++; = *(p++); 仅仅是个bug,无法解释通顺。 |
44楼: | >>参与讨论 |
作者: IceAge 于 2005/7/19 23:44:00 发布:
这个问题怎么还没完哪 *p++, *(p++) : compiler 是人做出来的,应该从计算机词法解析的角度去看。 这里的中心词是 p, 从p 向右看是 ++, 那么++立即与 p 结合成为p++,由于 右++是滞后操作,所以这里返还 p, 再向右,遇到)向左,则遇到 (, 形成 (p), 同理向左 =, 向右*, 则结合*, 成为 *(p). 当所有操作完成后,p+1. *p++ ... 等同于 *p ... , p++ *(p++) ... 等同于 *(p) ... , p++ |
45楼: | >>参与讨论 |
作者: 赤铸 于 2005/7/20 1:04:00 发布:
*优先级更高?不要乱说 下面是从帮助文件里拷贝的优先级顺序,同一行为同一优先级 () [] -> :: . left to right ! ~ + - ++ -- & * sizeof new delete right to left .* ->* left to right * / % left to right + - left to right << >> left to right < <= > >= left to right == != left to right & left to right ^ left to right | left to right && left to right || right to left ?: left to right = *= /= %= += -= &= ^= |= <<= >>= right to left , left to right ++和*在同一行,优先级相同,但单目运算符的结合方式为自右向左,所以*p++,*++p中,都是先执行“++” 如果是++*p,那就是先执行“*”了 |
46楼: | >>参与讨论 |
作者: dragonyu 于 2005/7/20 10:32:00 发布:
有少数的编译器可能出现不一样的结果,很正常的。 所以先看编译器了。不过大部分编译器是不会出问题的。 |
47楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/20 10:56:00 发布:
IceAge说的对,按优先级解释不通 x++就是滞后加,必须语句完后有效。 比如 unsigned int i = 0x6001; P1 = i ++ >>8; P2 = i; |
48楼: | >>参与讨论 |
作者: computer00 于 2005/7/20 11:30:00 发布:
你看看它被优化成什么样子了? 代码段一,使用*p++ 18: void main(void) 19: { 20: unsigned CHAR i; 21: unsigned CHAR data x[60]; 22: unsigned CHAR data * p; 23: p=x; C:0x0003 7F08 MOV R7,#0x08 ;将x[60]的地址保存到R7 24: for(i=0;i<10;i++) C:0x0005 E4 CLR A C:0x0006 FE MOV R6,A 25: { 26: *p++=i; C:0x0007 AD07 MOV R5,0x07 ;将R7的值暂存到R5 C:0x0009 0F INC R7 ;修改R7 C:0x000A A805 MOV R0,0x05 ;将R5的值放入R0 C:0x000C A606 MOV @R0,0x06 ;使用R0间址寻址 27: } C:0x000E 0E INC R6 C:0x000F BE0AF5 CJNE R6,#0x0A,C:0007 28: while(1); C:0x0012 80FE SJMP C:0012 因为要先使用,再修改值,所以编译器将地址放到另一个地方暂存了 这样看来似乎浪费了指令 代码段二,使用*p,p++ 18: void main(void) 19: { 20: unsigned CHAR i; 21: unsigned CHAR data x[60]; 22: unsigned CHAR data * p; 23: p=x; C:0x0003 7808 MOV R0,#0x08 ;同上 24: for(i=0;i<10;i++) C:0x0005 E4 CLR A C:0x0006 FF MOV R7,A 25: { 26: *p=i; C:0x0007 A607 MOV @R0,0x07 ;使用R0间址寻址 27: p++; C:0x0009 08 INC R0 ;修改R0 28: } C:0x000A 0F INC R7 C:0x000B BF0AF9 CJNE R7,#0x0A,C:0007 29: while(1); C:0x000E 80FE SJMP C:000E 以上代码使用KEIL C 2.38版本编译的结果,使用默认的优化配置。 * - 本贴最后修改时间:2005-7-20 11:57:15 修改者:computer00 |
49楼: | >>参与讨论 |
作者: computer00 于 2005/7/20 11:34:00 发布:
使用*p++看看它被“优化”成什么样子了? 代码段一,使用*p++ 18: void main(void) 19: { 20: unsigned CHAR i; 21: unsigned CHAR data x[60]; 22: unsigned CHAR data * p; 23: p=x; C:0x0003 7F08 MOV R7,#0x08 ;将x[60]的地址保存到R7 24: for(i=0;i<10;i++) C:0x0005 E4 CLR A C:0x0006 FE MOV R6,A 25: { 26: *p++=i; C:0x0007 AD07 MOV R5,0x07 ;将R7的值暂存到R5 C:0x0009 0F INC R7 ;修改R7 C:0x000A A805 MOV R0,0x05 ;将R5的值放入R0 C:0x000C A606 MOV @R0,0x06 ;使用R0间址寻址 27: } C:0x000E 0E INC R6 C:0x000F BE0AF5 CJNE R6,#0x0A,C:0007 28: while(1); C:0x0012 80FE SJMP C:0012 因为要先使用,再修改值,所以编译器将地址放到另一个地方暂存了 这样看来使用*p++似乎浪费了指令? 代码段二,使用*p,p++ 18: void main(void) 19: { 20: unsigned CHAR i; 21: unsigned CHAR data x[60]; 22: unsigned CHAR data * p; 23: p=x; C:0x0003 7808 MOV R0,#0x08 ;同上 24: for(i=0;i<10;i++) C:0x0005 E4 CLR A C:0x0006 FF MOV R7,A 25: { 26: *p=i; C:0x0007 A607 MOV @R0,0x07 ;使用R0间址寻址 27: p++; C:0x0009 08 INC R0 ;修改R0 28: } C:0x000A 0F INC R7 C:0x000B BF0AF9 CJNE R7,#0x0A,C:0007 29: while(1); C:0x000E 80FE SJMP C:000E 以上代码使用KEIL C 2.38版本编译的结果,使用默认的优化配置。 或许使用其它编译器或者是不同的CPU,可能会生成不一样的代码, 或许会有所优化,不过我没时间去试验了。我还是比较喜欢分开写。 * - 本贴最后修改时间:2005-7-20 11:55:15 修改者:computer00 |
50楼: | >>参与讨论 |
作者: wang5430 于 2005/7/20 11:39:00 发布:
经典 经典 * - 本贴最后修改时间:2005-7-20 11:45:13 修改者:wang5430 |
51楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/20 11:45:00 发布:
全世界农民都知道*P++比*P,P++优化的道理 你那个测试代码不典型,偶尔在51上才这样。你在*p,p++中加入其它指针操作后再比较就比较合理。 数组定义都是idata类型才合理。(再次废话) |
52楼: | >>参与讨论 |
作者: computer00 于 2005/7/20 12:57:00 发布:
按照所长的提示,我又重新写了个测试代码: 将所有数组设定为idata型。 81: void main(void) 82: { 83: unsigned CHAR idata * p1; 84: unsigned CHAR idata * p2; 85: unsigned CHAR idata x[100]; 86: unsigned CHAR idata y[10]; 87: unsigned CHAR i; 88: p1=x; C:0x0003 7F08 MOV R7,#0x08 89: p2=y; C:0x0005 7E6C MOV R6,#0x6C 90: for(i=0;i<10;i++) C:0x0007 E4 CLR A C:0x0008 FD MOV R5,A 91: { 92: *p1++=*p2++; C:0x0009 AC06 MOV R4,0x06 C:0x000B 0E INC R6 C:0x000C A804 MOV R0,0x04 C:0x000E E6 MOV A,@R0 C:0x000F AB07 MOV R3,0x07 C:0x0011 0F INC R7 C:0x0012 A803 MOV R0,0x03 C:0x0014 F6 MOV @R0,A 93: } C:0x0015 0D INC R5 C:0x0016 BD0AF0 CJNE R5,#0x0A,C:0009 94: } 81: void main(void) 82: { 83: unsigned CHAR idata * p1; 84: unsigned CHAR idata * p2; 85: unsigned CHAR idata x[100]; 86: unsigned CHAR idata y[10]; 87: unsigned CHAR i; 88: p1=x; C:0x0003 7F08 MOV R7,#0x08 89: p2=y; C:0x0005 7E6C MOV R6,#0x6C 90: for(i=0;i<10;i++) C:0x0007 E4 CLR A C:0x0008 FD MOV R5,A 91: { 92: *p1=*p2; C:0x0009 A806 MOV R0,0x06 C:0x000B E6 MOV A,@R0 C:0x000C A807 MOV R0,0x07 C:0x000E F6 MOV @R0,A 93: p1++; C:0x000F 0F INC R7 94: p2++; C:0x0010 0E INC R6 95: } C:0x0011 0D INC R5 C:0x0012 BD0AF4 CJNE R5,#0x0A,C:0009 96: } 编译环境为KEIL C 2.38版本,使用默认优化。 我不知道所长所说的典型是怎样的?难道这样使用指针还不是典型的吗? 我只知道我用指针时,绝大多数时间是这样用的。 除非把指针放到idata或者xdata中,可能因为对指针运算时,要用间接寻址, *p++可能被优化了。但是我认为在“典型”应用中,绝大部分是把指针放在 可直接寻址的范围内,这样有利于提高运行速度。除非是迫不得已才将指针放 在间接寻址区,但那就不能算“典型”了吧? 在X86的系统中,可能工作寄存器有限,使用*p++也许可以优化代码,我没实验 过。但是我想可以指定指针为寄存器变量啊。 所以我觉得没必要用*p++这样的“劳命伤财”的代码。除非在某些很特殊的情况 下,代码必须要足够优化时,才可以考虑改用*p++这样的代码来试试。 平时还是分开写得好,看起来都舒服多了,思维也习惯。 * - 本贴最后修改时间:2005-7-20 15:06:36 修改者:computer00 |
53楼: | >>参与讨论 |
作者: stevenxu 于 2005/7/20 14:27:00 发布:
这个问题的关键在于 p++这个表达式的“值”是什么?正确答案是p(旧的p),而不是(p+1)。当(p++)在一个复杂表达式里面参加运算,就相当于p参加运算,而不是(p+1)。 |
54楼: | >>参与讨论 |
作者: gwnpeter 于 2005/7/20 14:40:00 发布:
很多时候自己仿真一下就知道了 不外呼几行程序 |
55楼: | >>参与讨论 |
作者: IceAge 于 2005/7/20 20:48:00 发布:
To Computer00: Keil C 用最懒惰的方法实现了*p++ 并不表示所有的编译器都是这样。c++里的operator++是函数,无法联系上下文,而compiler 做的到。 如果keilC 里 p++被做成 TEMP = p; ++p; return TEMP; 而不是*p, p++的形式,那是keil C 的优化没有到位。 ______________________________________________________________________ IceAge 发表于 2005-7-16 23:13 侃单片机 ←返回版面 举报该贴 如果做过c++ 里的operator++(++ 的重载),就非常清楚。 p++ 保存 p 的copy 后将 p +1, 然后返回 p 的copy. 在当前的作用域内使用的全是 p 的copy, 不是 p !!!. 所以有没有 (),效果是一样的。 例如: gg += mm++ 实际为 1) mm++ ----> 返回 mm 的copy MM, mm+1; 2) gg += MM //www.21icbbs.com/club/bbs/showannounce.asp?id=1739359 |
56楼: | >>参与讨论 |
作者: computer00 于 2005/7/20 21:58:00 发布:
我不是说了?这个只是在keil C2.38版本下测试的,使用默认优化级 以上代码使用KEIL C 2.38版本编译的结果,使用默认的优化配置。 或许使用其它编译器或者是不同的CPU,可能会生成不一样的代码, 或许会有所优化,不过我没时间去试验了。 |
57楼: | >>参与讨论 |
作者: 汽车电子 于 2005/7/20 23:34:00 发布:
这是C语言的基础东东 p++是先取p值,后加 ++p是先加,后取p值 |
58楼: | >>参与讨论 |
作者: 北方老郎 于 2005/7/20 23:54:00 发布:
不要偷懒 对于不确定的C语句,最好使用确定的方式来写,使代码无论用那个编译器都一样。如*p++=n,如果作者想赋值之后调整指针,则应该写成*p=n;p++;如果想赋值之前调整指针,则应该写成p++;*p=n; 写程序应该养成良好的习惯。又如if(a&b&&c&d)这样的语句最好写成 if((a&b)&&(c&d)),才不至于产生莫名其妙的错误,折腾你好几天。 |
59楼: | >>参与讨论 |
作者: 赤铸 于 2005/7/21 1:29:00 发布:
其实*p++不可能非常优化,倒是*++p可能很优化 如果注重效率,设计循环时调整一下下标,改用*++p,*--p,会有好处的 |
60楼: | >>参与讨论 |
作者: wy051 于 2005/7/21 10:08:00 发布:
*P++优于*P=n;*P++; 在下例是讲解,把字符串指针作为函数参数的使用。要求把一个字符串的内容复制到另一个字符串中,并且不能使用strcpy函数。函数cprstr的形参为两个字符指针变量。pss指向源字符串,pds指向目标字符串。表达式: (*pds=*pss)!=`\0' cpystr(CHAR *pss,CHAR *pds){ while((*pds=*pss)!='\0'){ pds++; pss++; } } main(){ CHAR *pa="CHINA",b[10],*pb; pb=b; cpystr(pa,pb); printf("string a=%s\nstring b=%s\n",pa,pb); } 在上例中,程序完成了两项工作:一是把pss指向的源字符复制到pds所指向的目标字符中,二是判断所复制的字符是否为`\0',若是则表明源字符串结束,不再循环。否则,pds和pss都加1,指向下一字符。在主函数中,以指针变量pa,pb为实参,分别取得确定值后调用cprstr函数。由于采用的指针变量pa和pss,pb和pds均指向同一字符串,因此在主函数和cprstr函数中均可使用这些字符串。也可以把cprstr函数简化为以下形式: cprstr(CHAR *pss,CHAR*pds) {while ((*pds++=*pss++)!=`\0');} 即把指针的移动和赋值合并在一个语句中。 进一步分析还可发现`\0'的ASCⅡ码为0,对于while语句只看表达式的值为非0就循环,为0则结束循环,因此也可省去“!=`\0'”这一判断部分,而写为以下形式: cprstr (CHAR *pss,CHAR *pds) {while (*pdss++=*pss++);} 表达式的意义可解释为,源字符向目标字符赋值, 移动指针,若所赋值为非0则循环,否则结束循环。这样使程序更加简洁。 Lunix 里字符串拷贝函数也是这么写的,应该有它的道理! |
61楼: | >>参与讨论 |
作者: IceAge 于 2005/7/21 11:46:00 发布:
To: wy051 除非是特殊的cpu(比如ti dsp, *p++=n 可以用一条汇编指令完成), 否则执行效率上*p++ 不会优于*P=n;P++;。 但简洁对程序员有无比的吸引力, 甚至会放弃对效率的追求。 |
62楼: | >>参与讨论 |
作者: 农民讲习所 于 2005/7/21 11:51:00 发布:
*p++这条语句的存在,就是为优化而生存的。 至于编译器做得好不好,那是它的事情。 |
63楼: | >>参与讨论 |
作者: wy051 于 2005/7/21 12:05:00 发布:
同意---- 程序员考试中有好多题就是专门考这个的! |
64楼: | >>参与讨论 |
作者: wy051 于 2005/7/21 12:06:00 发布:
再顶一下 *(P++)不是什么好习惯,但*P++决对是! |
65楼: | >>参与讨论 |
作者: yangfan64 于 2005/7/23 8:58:00 发布:
无意义的问题 即使是高手如果有一段时间没编程都可能搞不清这个问题,不过花几秒钟试一下不就什么都清楚了? |
66楼: | >>参与讨论 |
作者: hanyc 于 2005/7/23 13:03:00 发布:
只要++在后面,就一定后执行,在前面就先执行。这还用讨论。 一个字,笨哪。 |
67楼: | >>参与讨论 |
作者: bilborn258 于 2005/7/24 9:01:00 发布:
我比较弱智 我从来不靠记这些东西充高手的。打个括号不就搞定了吗? |
68楼: | >>参与讨论 |
作者: makesoft 于 2005/7/24 10:51:00 发布:
楼上,这不是打个括号就能解决问题的? *(p++)能得到你括号的效果吗? |
69楼: | >>参与讨论 |
作者: mmd 于 2005/7/24 19:08:00 发布:
代码存在的意义在于执行。 停留在对高手的幻觉中,就会对骨骼怪异的代码费心思; 了解你的目标芯片,了解你的编译器。 最优条件下,不会因为你少些了几行代码,cpu就会少运行几个周期而得到相同的结果。 最好的代码不是最少的代码,因为人和机器都要用。 |
70楼: | >>参与讨论 |
作者: 最爱韶涵 于 2005/7/24 23:41:00 发布:
支持*p++,从来不觉得它有什么不对 |
71楼: | >>参与讨论 |
作者: st963432 于 2005/7/25 9:52:00 发布:
1. |
72楼: | >>参与讨论 |
作者: zzyszl 于 2005/7/25 9:58:00 发布:
(1)a[0]=n;(2)p++ (1)a[0]=n; (2)p++ |
73楼: | >>参与讨论 |
作者: yellowland 于 2005/7/26 15:38:00 发布:
做产品的不准写出这种代码 在公司,这种代码要罚钱的,降薪,开除.没谁和你讨论对错的问题 |
74楼: | >>参与讨论 |
作者: mailbert 于 2005/7/27 12:46:00 发布:
靠!研究这有什么意义?多写一行不就得了! |
75楼: | >>参与讨论 |
作者: jlspwtg 于 2005/7/28 12:26:00 发布:
狗屁问题! |
76楼: | >>参与讨论 |
作者: greatbin 于 2005/7/28 12:52:00 发布:
讨论什么,无聊的问题,还高手会错 |
77楼: | >>参与讨论 |
作者: 57785461 于 2005/7/28 18:09:00 发布:
很有建树的讨论 顶 |
78楼: | >>参与讨论 |
作者: net_hawk 于 2005/7/29 13:08:00 发布:
优先级++先 a[1]=n; |
79楼: | >>参与讨论 |
作者: zhaoda 于 2005/7/30 17:03:00 发布:
这还不容易 写段程序, 跟踪到汇编不就明白了 |
80楼: | >>参与讨论 |
作者: clou_jhl 于 2005/8/1 16:52:00 发布:
加括号就好使了 |
81楼: | >>参与讨论 |
作者: zslw 于 2005/8/1 16:53:00 发布:
不知道在keil c里面有没有什么不同的 说的优化是不是生成的指令不同啊 |
82楼: | >>参与讨论 |
作者: cbb0201 于 2005/8/1 19:24:00 发布:
什么? 实际运行一下不就可以了. |
83楼: | >>参与讨论 |
作者: yinyiying 于 2005/8/1 20:53:00 发布:
实践是检验真理的唯一标准! 大体的读了这些帖子后想想自己平时的工作,想到这句真理! |
84楼: | >>参与讨论 |
作者: liumsn 于 2005/8/2 9:10:00 发布:
打个括号不就行了 这种问题真无聊,你讨论清楚又能如何呢?根据需要的结果在表达式里打个括号不就得了!搞清楚你就比高手还厉害了吗? |
85楼: | >>参与讨论 |
作者: vwwj 于 2005/8/2 11:16:00 发布:
本来就没意义的问题 就是这样吵,才把张纪中吵成金庸专业户的。 |
|
|
Copyright © 1998-2006 lahealthsma.com 浙ICP证030469号 |