学习型 ASP/PHP/ASP.NET 主机 30元/年全能 ASP/PHP/ASP.NET 主机,支持月付专业 MSSQL 数据库空间,支持月付专业 MySQL 数据库空间,支持月付
 17 12
发新话题
打印

有点疑问,请教大家。小女子谢谢

有点疑问,请教大家。小女子谢谢

1、
int main()
{
    const int a=0;
    int *p=(int*)&a;

    *p=3;
    printf("a=%d,*p=%d\n",a,*p);

    return 0;
}
输出结果:a=0,*p=3   
2、
int main()
{
     int a=0;
    const int *p=&a;

    a=3;
    printf("a=%d,*p=%d\n",a,*p);

    return 0;
}
输出结果:a=3,*p=3
1)为什么前面的a不是等于3,我认为a所在的内存地址里的值已经改为3了,按道理a对应的值也应该 是3.或许你们会认为因为a是const变量,那好看下面
2)按照第一题的输出结果,那为什么第二题*p的值又改变为3了呢??它指向的值不也是const的。
请教高手解释下,这个两个结果我认为有矛盾之处。

TOP

编译系统的问题吧

我用win-tc运行后a=3,*p=3
编程快乐,快乐编程! 没有最好,只有更好!

TOP

恩``我运行2个程序都和LS一样``结果都是3
女施主``我给你``送茶来了```师太``你就从了老衲吧``
代码本天成~~~妙头偶得之```
www.yzfy.org    yzfy.5d6d.com

TOP

这个问题应该这么看。首先通过指针去掉变量的const属性的行为是未定义的,讨论起来其实没什么意义。然后我们分析一下这个结果是怎么来的。
下面是一段GCC编译过后的代码:
    movl    $3, -4(%ebp)
    leal    -4(%ebp), %eax
    movl    $3, %edx
    movl    %eax, 16(%esp)
    movl    %eax, 12(%esp)
    xorl    %eax, %eax
    movl    %edx, 8(%esp)
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf

可以明显看出,因为a是常数,因此在使用a的时候,编译器直接使用了a的值,而不是从a的内存地址读取a的值。
但在VC编译的时候,因为过度优化,编译器直接写0,3两个数字进去了。所以我给a加了一个属性,如下:
volatile const int a=3;
强迫编译器,每次都要读a的值。于是在VC下,第一个程序的输出变成了a=3,p=3
但是在GCC下无效。观察源代码发现,编译器对a的值的改变在printf语句的后面(ft……)可能是编译器认为既然使用a的值的时候,a的值并没有改变。所以两条语句的顺序可以随意改变吧……反正这么写
    volatile const int a=0;
    int *p=(int*)&a;

    *p=3;
    printf("a=%d,*p=%d\n",a,*p);
    printf("a=%d",a);
输出的结果是a=0,*p=3,a=3………………这个么,这个应该不算编译器Bug,因为编译器不必为这种行为负责:改变常量的行为本身就是未定义的……

第二个问题很简单。p的确是指向常量的指针。但是a不是常量啊,a的值是可以改变的。所以a改变以后,p的值也跟着改变咯……
专心编程………
飞燕算法初级群:3996098
我的Blog

TOP

翅膀还可以把汇编注释下啊?-4(%ebp)?是什么?
学习需要安静。。海盗要重新来过。。

TOP

Orz……大家都不懂汇编么?
首先,ebp-4是a的地址。然后要调用printf对吧?下面的代码推入了几个值。

    movl    $3, -4(%ebp);3移入a
    leal    -4(%ebp), %eax;a的地址移入eax
    movl    $3, %edx;3移入edx
    movl    %eax, 16(%esp);这两行其实可以无视掉,主要是我确定
    movl    %eax, 12(%esp);p的值和a的地址是不是一样的,答案……可以看出来了……
    xorl    %eax, %eax;eax清0,注意a的初始值等于0,这里明显使用了a的原值(而不是现在a的值,注意a已经被改成3了……)
    movl    %edx, 8(%esp);还记得edx么?是3
    movl    %eax, 4(%esp);eax是0
    movl    $LC0, (%esp);字符串"a=%d,*p=%d"
    call    _printf;调用printf
专心编程………
飞燕算法初级群:3996098
我的Blog

TOP

上面是没有加volatile的版本。下面是加了volatile的版本……Orz……已经对GCC编译器无语了……
源代码:
#include <stdio.h>

int main()
{
    volatile const int a=0;
    int *p=(int*)&a;

    *p=3;
    printf("a=%d,*p=%d\n",a,*p);

    return 0;
}

汇编代码:
    movl    $0, -4(%ebp);a赋初值
    movl    $3, %eax;eax赋3
    movl    %eax, 8(%esp);eax的值入栈
    movl    -4(%ebp), %eax;a的值存入eax,我的天哪,3这个值还没有写入a……服了GCC了……
    movl    $3, -4(%ebp);这个时候把3写进a,是不是晚了点……
    movl    $LC0, (%esp);字符串入栈
    movl    %eax, 4(%esp);写a,Orz,eax这个时候是0……
    call    _printf;调用……

看完汇编代码,对GCC完全FT了……
专心编程………
飞燕算法初级群:3996098
我的Blog

TOP

去掉了const修饰符以后,代码如下:
    movl    $0, -4(%ebp)
    movl    $3, %eax
    movl    $3, -4(%ebp)
    movl    %eax, 8(%esp)
    movl    -4(%ebp), %eax
    movl    $LC0, (%esp)
    movl    %eax, 4(%esp)
    call    _printf
专心编程………
飞燕算法初级群:3996098
我的Blog

TOP

我大三得时候学的汇编现在指令忘得差不多了...有时间还是要看看
学习需要安静。。海盗要重新来过。。

TOP

回复 6# 的帖子

谢谢!

TOP

 17 12
发新话题