天玺体育最火网上大全

登录 免费注册 天玺体育最火网上大全 | 行业黑名单 | 帮助
维库电子市场网
技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | 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楼: >>参与讨论
艾森豪威尔
难道不是先a[0]=n,再p++吗?
 
3楼: >>参与讨论
lczsx2000
*p = n; p++;
 
4楼: >>参与讨论
AVRx007
后加。 不应该搞错的。
 
5楼: >>参与讨论
IceAge
想问一下, 是 那本书上说是p++,a[1]=n; ?
 
6楼: >>参与讨论
xwj
写书的作者自己都没搞懂就乱说一气
天下文章一大抄,错都错得一模一样,真是让人气愤!

大家把自己的书看看,估计很多书都有这样的话;

“*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
尽信书不如无书。
以前的高手写书还有点道德。
现在,一切向"钱"看.

网络上更多谣传的,很多网站,转载别人的也不考究一下,而且脸皮特厚,还老说是自己写的。

8楼: >>参与讨论
艾森豪威尔
哪本数?书名是什么?
 
9楼: >>参与讨论
农民讲习所
别再深究了,估计是原贴写错了
把(*p)++写错为*(p++),估计不是书的错,因为后面的话是对的。

10楼: >>参与讨论
wy051
楼主真的开贴讨论了!!!!!!
为了更好的搞清楚这个*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
为什么要写这样的代码呢?我就从来不干这种劳命伤财的事
分开两句来写,不是好得很?

*p=n;
p++;

一看就明白。

12楼: >>参与讨论
xwj
自认高手的先看这个贴,看看自己是否还有不足
 


13楼: >>参与讨论
农民讲习所
还要在这里再说一遍,麻烦
书上对的,*p++ 和 *(p++)结果是一样的。

误导教唆犯,犯罪了。
没用过*(p++),农民见识少点,别丢砖头过来了。

14楼: >>参与讨论
liudewei
本以为++优先级高于*
其实从右至左,看来括号不能轻易省

* - 本贴最后修改时间:2005-7-13 15:51:06 修改者:liudewei

15楼: >>参与讨论
yewuyi
忍不住问两句
XWJ的问题,我肯定是选择第一个答案。

首先声明:
我不会用C,只是以前偶尔偷“摸”了两把(呵呵,不会有人说我非礼把)。

在我学习C的过程中,从来都认为*(P++) != *P++

在KEIL里面为何两种编译结果相同,我是没搞明白?是不是因为历史的缘故?

从ANSI-C语法上分析,两者能等同吗?即使不推荐那种写法,但从C规则来讲,这两种写法是否确实是等同的呢?


还望所长&xwj及其他朋友指教。

16楼: >>参与讨论
athlon64fx
re
*p = n;
p++;

*p++ = n;
编译结果未必一样,虽然运行结果是相同的.
*p++ 可能直接使用 CPU 带"后加"的指令.

关于 *p++ 和 *(p++) 这个 too simple,sometimes naive 的问题,
请考虑 p++ 和 ++p.

17楼: >>参与讨论
AVRx007
我认为这是编译器的BUG.
*p++  先读/写  后加指针。
*++p  先加指针 后读/写。

*p--  先读/写  后减指针。
*--p  先减指针 后读/写。

AVR的指令就有后加和预减,以实现高速读写。
  LD Rd,X+  ST X+,Rr [*p++]
  LD Rd,-X  ST -X,Rr [*--p]



18楼: >>参与讨论
hotpower
1.
 
19楼: >>参与讨论
yewuyi
关于 *p++ 和 *(p++) 这个 too simple,sometimes naive 的问题
simple and naive也不是什么坏事情.


简单的问题对于没有掌握它的人来说就是一个天大的难题……


……

20楼: >>参与讨论
xwj
经测试,*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
应该是1吧.试一下就知道了.不过拒绝写这种代码
现在不爱去想优先级的问题了,不确定,加括号,反正又不会造成不好后果.

花那么多时候去想干嘛(头儿这么教育的:)),又不是在考试...

22楼: >>参与讨论
mikejx
现在就连加括号前也要想想有什么后果
c就这些规则太麻烦了

23楼: >>参与讨论
xwj
有时括号也不可靠
这个问题就是由括号带来的,
在别的帖子讨论*p++ 和 *(p++)是不是一样,结果却出乎意料,
估计和很多人猜想的不一样


有些东西没试过还真不好说

24楼: >>参与讨论
computer00
C语言不是规定了吗?对于p++,是先取值,后++
而括号是并不影响这个操作的。会先用p的值计算,遇到分号后,才会执行++。
所以使用p++时,是相当于把p=p+1;放到了下面一条语句。
你不要认为加了一个括号就会让它先运算了。
后加1操作是对整条语句来说的,跟括号没关系。

25楼: >>参与讨论
hotpower
computer00看的是"水气"
P++必须等该语句执行完后下一语句才真正的P++,真与括号无关.

括号也只能负责本条语句,它再大的能耐也管不了下句!!!

26楼: >>参与讨论
computer00
"水气",我还"热水器"呢,怎么说也得要跟你这个"热水"扯上点关系
 
27楼: >>参与讨论
liudewei
是的,这一句括号还不管用,真没有这样用过
 
28楼: >>参与讨论
long8725
烦,还想误导
 
29楼: >>参与讨论
边锋
很简单,防真一下就什么都明白了!
很简单,防真一下就什么都明白了!

30楼: >>参与讨论
笨笨兔
哈哈,同样的话题
嘿嘿,这个问题上周六我也思考过,试图从运算符的结合顺序及其优先级去分析,歪写了一篇:
//www.21icbbs.com/club/bbs/ShowAnnounce.asp?v=&ID=1739180
虽然是投机的分析,但对记忆有点帮助呢。

已经建议公司的Coding Rule中增加:除了大家非常清楚的 *p++的写法外,其他包含 ++、--的算式,一律分开写。毕竟产品追求的是可靠性,换个人来,不至于又理解错了。

而且 诸如 TEMP = *p++;的写法,跟 写成 TEMP= *p; p++;编译效率几乎一致,初学者也都看得懂,可是再写成 TEMP = *(p++)的话,相信多数人都会理解错!


31楼: >>参与讨论
shanyongde
这是我在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楼: >>参与讨论
波动光学
a[0]=n,再p++;
先a[0]=n,再p++,p指向a[1]!

33楼: >>参与讨论
hunter01
这样写,代码的速度快了吗?劳民伤财,
而且不一定每次用完指针都要加1。把人会搞糊涂的嘿嘿,

34楼: >>参与讨论
canycao
看编译器的,不同的编译器出来的结果不同
做过类似的试验,用了TC,VC++...等不同6、7种不同的编译环境,出来的结果是不一样的。

35楼: >>参与讨论
xxlale
IGBT的使用
我想实现单片机输出控制大功率的继电器,除了正反向二极管之外,可不可以使用IGBT,如何实现?

36楼: >>参与讨论
victorymay
"++"应先级高于* -
 
37楼: >>参与讨论
lhkjg
就是就是,这样的代码称之为“垃圾代码”
 
38楼: >>参与讨论
农民讲习所
*p++可被优化,*p,p++不能。
 
39楼: >>参与讨论
refugee
++在后,是先操作后在自加1
 
40楼: >>参与讨论
赤铸
说白了还是基本概念问题
C语言的一个重要特性就是表达式与执行语句的重叠,一个重要概念就是表达式的“值”(真正理解这个概念的人不多,哪怕是一些资深工程师)
而整体加括号是不影响表达式的值的,所以表达式p++和(p++)的值完全相等,由于++优先级更高,表达式*p++与*(p++)的值也完全相等


41楼: >>参与讨论
yadog
指针
路过

42楼: >>参与讨论
elelab
矛盾,连这个都搞错还是高手啊
 
43楼: >>参与讨论
AVRx007
在*p++中,明明是*的优先级高于++,怎么还有人乱说什么基本概念?
*p++; = *p;    p++;  
*p++; = *(p++);      仅仅是个bug,无法解释通顺。

44楼: >>参与讨论
IceAge
这个问题怎么还没完哪
*p++, *(p++) : compiler 是人做出来的,应该从计算机词法解析的角度去看。
这里的中心词是 p, 从p 向右看是 ++, 那么++立即与 p 结合成为p++,由于 右++是滞后操作,所以这里返还 p,  再向右,遇到)向左,则遇到 (, 形成 (p), 同理向左 =, 向右*, 则结合*, 成为 *(p). 当所有操作完成后,p+1.

*p++ ... 等同于 *p ... , p++
*(p++) ... 等同于 *(p) ... , p++




45楼: >>参与讨论
赤铸
*优先级更高?不要乱说
下面是从帮助文件里拷贝的优先级顺序,同一行为同一优先级

()  []  ->  ::  .                           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
有少数的编译器可能出现不一样的结果,很正常的。
所以先看编译器了。不过大部分编译器是不会出问题的。 

47楼: >>参与讨论
农民讲习所
IceAge说的对,按优先级解释不通
x++就是滞后加,必须语句完后有效。

比如
     unsigned int i = 0x6001;

     P1 = i ++ >>8;
     P2 = i;


48楼: >>参与讨论
computer00
你看看它被优化成什么样子了?
代码段一,使用*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
使用*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:45:13 修改者:wang5430

51楼: >>参与讨论
农民讲习所
全世界农民都知道*P++比*P,P++优化的道理
你那个测试代码不典型,偶尔在51上才这样。你在*p,p++中加入其它指针操作后再比较就比较合理。

数组定义都是idata类型才合理。(再次废话)

52楼: >>参与讨论
computer00
按照所长的提示,我又重新写了个测试代码:
将所有数组设定为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
这个问题的关键在于
p++这个表达式的“值”是什么?正确答案是p(旧的p),而不是(p+1)。当(p++)在一个复杂表达式里面参加运算,就相当于p参加运算,而不是(p+1)。

54楼: >>参与讨论
gwnpeter
很多时候自己仿真一下就知道了
不外呼几行程序

55楼: >>参与讨论
IceAge
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
我不是说了?这个只是在keil C2.38版本下测试的,使用默认优化级
以上代码使用KEIL C 2.38版本编译的结果,使用默认的优化配置。
或许使用其它编译器或者是不同的CPU,可能会生成不一样的代码,
或许会有所优化,不过我没时间去试验了。




57楼: >>参与讨论
汽车电子
这是C语言的基础东东
   p++是先取p值,后加
   ++p是先加,后取p值

58楼: >>参与讨论
北方老郎
不要偷懒
    对于不确定的C语句,最好使用确定的方式来写,使代码无论用那个编译器都一样。如*p++=n,如果作者想赋值之后调整指针,则应该写成*p=n;p++;如果想赋值之前调整指针,则应该写成p++;*p=n;
    写程序应该养成良好的习惯。又如if(a&b&&c&d)这样的语句最好写成
if((a&b)&&(c&d)),才不至于产生莫名其妙的错误,折腾你好几天。

59楼: >>参与讨论
赤铸
其实*p++不可能非常优化,倒是*++p可能很优化
如果注重效率,设计循环时调整一下下标,改用*++p,*--p,会有好处的

60楼: >>参与讨论
wy051
*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
To: wy051
除非是特殊的cpu(比如ti dsp, *p++=n 可以用一条汇编指令完成), 否则执行效率上*p++ 不会优于*P=n;P++;。 但简洁对程序员有无比的吸引力, 甚至会放弃对效率的追求。

62楼: >>参与讨论
农民讲习所
*p++这条语句的存在,就是为优化而生存的。
至于编译器做得好不好,那是它的事情。

63楼: >>参与讨论
wy051
同意----
程序员考试中有好多题就是专门考这个的!

64楼: >>参与讨论
wy051
再顶一下
*(P++)不是什么好习惯,但*P++决对是!

65楼: >>参与讨论
yangfan64
无意义的问题
即使是高手如果有一段时间没编程都可能搞不清这个问题,不过花几秒钟试一下不就什么都清楚了?

66楼: >>参与讨论
hanyc
只要++在后面,就一定后执行,在前面就先执行。这还用讨论。
一个字,笨哪。

67楼: >>参与讨论
bilborn258
我比较弱智
我从来不靠记这些东西充高手的。打个括号不就搞定了吗?

68楼: >>参与讨论
makesoft
楼上,这不是打个括号就能解决问题的?
*(p++)能得到你括号的效果吗?

69楼: >>参与讨论
mmd
代码存在的意义在于执行。
停留在对高手的幻觉中,就会对骨骼怪异的代码费心思;

了解你的目标芯片,了解你的编译器。
最优条件下,不会因为你少些了几行代码,cpu就会少运行几个周期而得到相同的结果。

最好的代码不是最少的代码,因为人和机器都要用。

70楼: >>参与讨论
最爱韶涵
支持*p++,从来不觉得它有什么不对
 
71楼: >>参与讨论
st963432
1.
 
72楼: >>参与讨论
zzyszl
(1)a[0]=n;(2)p++


  (1)a[0]=n;

  (2)p++
   
   
   

73楼: >>参与讨论
yellowland
做产品的不准写出这种代码
在公司,这种代码要罚钱的,降薪,开除.没谁和你讨论对错的问题

74楼: >>参与讨论
mailbert
靠!研究这有什么意义?多写一行不就得了!
 
75楼: >>参与讨论
jlspwtg
狗屁问题!
 
76楼: >>参与讨论
greatbin
讨论什么,无聊的问题,还高手会错
 
77楼: >>参与讨论
57785461
很有建树的讨论


78楼: >>参与讨论
net_hawk
优先级++先 a[1]=n;
 
79楼: >>参与讨论
zhaoda
这还不容易
写段程序, 跟踪到汇编不就明白了

80楼: >>参与讨论
clou_jhl
加括号就好使了
 
81楼: >>参与讨论
zslw
不知道在keil c里面有没有什么不同的
说的优化是不是生成的指令不同啊

82楼: >>参与讨论
cbb0201
什么?
实际运行一下不就可以了.

83楼: >>参与讨论
yinyiying
实践是检验真理的唯一标准!
大体的读了这些帖子后想想自己平时的工作,想到这句真理!

84楼: >>参与讨论
liumsn
打个括号不就行了
这种问题真无聊,你讨论清楚又能如何呢?根据需要的结果在表达式里打个括号不就得了!搞清楚你就比高手还厉害了吗?

85楼: >>参与讨论
vwwj
本来就没意义的问题
  就是这样吵,才把张纪中吵成金庸专业户的。

参与讨论
昵称:
讨论内容:
 
 
相关帖子
电容储电
关于光电编码器的问题
请问哪位兄台能够提供写流程图的软件?象SmatDraw...
看看C语句都生成了什么汇编指令,并有问题请教
MCU51-63K仿真头是不是一定不能仿真串口?


Copyright © 1998-2006 lahealthsma.com 浙ICP证030469号