首页
论坛
课程
招聘
[旧帖] [原创]C语言-常量 0.00雪花
2011-5-27 00:25 3306

[旧帖] [原创]C语言-常量 0.00雪花

2011-5-27 00:25
3306
说明:东西都比较简单,个人水平也比较一般,表述难免不清或错误。自己学习的一点总结,还请各位多指教不足和要改进的地方,我会及时更新,这里先谢过。

上一篇 关于基本数据类型和局部变量链接:
http://bbs.pediy.com/showthread.php?p=963344#post963344

  C语言之常量
   C语言的常量主要只在编译前值就确定的数值,类型主要包括:整型常量,浮点型常量,字符型常量和枚举型常量。
   环境为win32,Vc
    示例代码:
#define MAX_NUM  256
const int g_cnTest = 123;

int main(int argc, char* argv[])
{
    //bool
    bool isTest = true;
    //char
    char cChar  = 'T';
    //int
    int nNum    = 0x123;
    nNum = MAX_NUM;
    int nMax = g_cnTest;
    //枚举
    typedef  enum EnTest{en_0, en_1, en_2};
    EnTest et = en_2;
    //float(double)
    float fValue = 1.2f;
    //double
    double dfValue1 = 1.2;
    double dfValue2 = 1.2;
    //字符串
    printf("Hello World!\r\n");
    char* lpTest = (char*)("Hello World!\r\n");

    return 0;
}
 

  数值型常量的表现
  类型为bool,char,int,float,double,enum
  
15:       //bool
16:       bool isTest = true;
0040E9D8 C6 45 FC [B][COLOR="Red"]01 [/COLOR] [/B]        mov         byte ptr [ebp-4],[B][COLOR="red"]1[/COLOR][/B]
17:       //char
18:       char cChar  = 'T';
0040E9DC C6 45 F8 [B][COLOR="red"]54[/COLOR] [/B]         mov         byte ptr [ebp-8],[B][COLOR="red"]54h[/COLOR][/B]
19:       //int
20:       int nNum    = [COLOR="red"]0x123[/COLOR];
0040E9E0 C7 45 F4 [B][COLOR="red"]23 01 00 00 [/COLOR][/B]mov         dword ptr [ebp-0Ch],[B]123h[/B]
21:       nNum = MAX_NUM;
0040E9E7 C7 45 F4 [B][COLOR="red"]00 01 00 00 [/COLOR][/B]mov         dword ptr [ebp-0Ch],[B][COLOR="red"]100h[/COLOR][/B]
22:       int nMax = cnTest;
0040E9EE C7 45 F0 [B][COLOR="red"]7B 00 00 00 [/COLOR][/B]mov         dword ptr [ebp-10h],[B][COLOR="red"]7Bh[/COLOR][/B]
23:       //枚举
24:       typedef  enum EnTest{en_0, en_1, [B]en_2[/B]};
25:       EnTest et = en_2;
0040E9F5 C7 45 EC [B][COLOR="red"]02 00 00 00 [/COLOR][/B]mov         dword ptr [ebp-14h],[B][COLOR="red"]2[/COLOR][/B]
28:       //float
29:       float fValue = 1.2f;
0040EA03 C7 45 E4 [COLOR="red"]9A 99 99 3F [/COLOR]mov         dword ptr [ebp-1Ch],[COLOR="red"][B]3F99999Ah[/B][/COLOR]
30:       //double
31:       double dfValue1 = 1.2;
0040EA0A C7 45 DC [COLOR="red"]33 33 33 33 [/COLOR]mov         dword ptr [ebp-24h],[COLOR="red"]33333333h[/COLOR]
0040EA11 C7 45 E0 [COLOR="red"]33 33 F3 3F [/COLOR]mov         dword ptr [ebp-20h],[COLOR="red"]3FF33333h[/COLOR]
32:       double dfValue2 = 1.2;
0040EA18 C7 45 D4 33 33 33 33 mov         dword ptr [ebp-2Ch],33333333h
0040EA1F C7 45 D8 33 33 F3 3F mov         dword ptr [ebp-28h],3FF33333h



  从汇编代码中可以得到一些规律:
  1)bool,char,int(包括#define )的字面常量值编成了操作数(立即数),直接使用,不需要寻址操作
    如nNum = 0x123
      对应的机器码为C7 45 E0 23 01 00 00 => 对应数值为0x123小尾方式存储。
   2)枚举型和const类型整型变量也当常量使用,直接编译到代码中。因为其值定义并初始化时,其值就是固定的,不会被修改。来试着修改下
      a) 直接修改
          nMax = ++g_cnTest;
              编译时提示需要左值,说明没有存储空间,编译器将其视作常量对待(编译器处理)。
      b) 通过取地址方式来修改,编译通过,执行时。。。
            
 int* lpInt = (int*)&g_cnTest;
 *lpInt = 0x111;

         
        因为const定义的值在常量区,而常量区的内存属性通常为可读不可写,有写操作时会触发系统的内存保护机制,就给你弹框。
   3) 机器码中数值长度跟具体的数据类型相关 (枚举这里貌似也是)
     4)浮点数是IEEE编码方式存储
   5)  此外还有一种情况就是在编译时,变量的值是可预测的,不变的(有的叫契约常量)。
    int nNum = 0x123;
    int nTest = nNum;
    printf("%d", nTest);
Debug方式下:
   int nNum = 0x123;
001F432E  mov         dword ptr [nNum],123h 
    int nTest = nNum;
001F4335  mov         eax,dword ptr [nNum] 
001F4338  mov         dword ptr [nTest],eax 
    printf("%d", nTest);
001F433B  mov         esi,esp 
001F433D  mov         eax,dword ptr [nTest] 
001F4340  push        eax  
001F4341  push        offset string "%d" (1F7818h) 
001F4346  call        dword ptr [__imp__printf (1FB2F0h)] 
Release方式:
text:00401003 8B 3D A0 20 40+    mov edi, ds:__imp__printf
.text:00401009 68 23 01 00 00     push [B][COLOR="Red"]123h[/COLOR][/B]
.text:0040100E 68 14 21 40 00     push offset Format                  ; "%d"
.text:00401013 FF D7              call edi ; __imp__printf

     
字符串
 [CODE]
33:       //字符串
34:       printf("Hello World!\r\n");
0040EA26 68 1C 40 42 00       push        offset string "My Hello World!\r\n" ([B][COLOR="red"]0042401c[/COLOR][/B])
0040EA2B E8 60 26 FF FF       call        printf (00401090)
0040EA30 83 C4 04             add         esp,4
35:       char* lpTest = (char*)("Hello World!\r\n");
0040EA33 C7 45 D0 1C 40 42 00 mov         dword ptr [ebp-30h],offset string "My Hello World!\r\n" ([B][COLOR="red"]0042401c[/COLOR][/B])


同样观察得到一些规律为:
  1) 字符串常量保存的在内存常量区中(属性一般为可读不可写),没有和代码编译在一起直接做值使用,在指令中通过获取指定地址来使用
      这里通过0x42401c来获取字符串内容
       0042401C      48 65 6C 6C 6F 20 57 6F 72 6C 64 21 0D 0A 00 00 7B       Hello World!
  2)值相等的字符串在内存中只会有一份,需要时获取即可。
     这里printf使用的字符串和初始化指针的地址都为【0042401c】
  3)对常量的修改同样是受到系统内存属性保护的约束, 一个C0xx05的错误没的跑。
     
 lpTest[0] = 'I';
0040EA43 8B 4D D0             mov         ecx,dword ptr [ebp-30h]
0040EA46 C6 01 49             mov         byte ptr [ecx],49h


   在调试状态,直接修改内存
  
0042401C  48 65 6C 6C 6F 20 57 6F 72 6C 64 21 0D 0A 00 00 7B 00  Hello World!  <--原来的
0042401C  48 65 6C 6C 6F 20 57 [COLOR="red"]4F 52 4C 44 [/COLOR]21 0D 0A 00 00 7B 00  Hello W[COLOR="red"]ORLD[/COLOR]!     <--直接修改内存

    这里怎么又可以修改了呢?
   主要是因为调试器的权限,比如下个软断点(修改代码+CC即int3),代码都能改,调试器还有啥做不到的呢。
总结:
  1)VC处理数值型常量时(bool, char, int, enum, const xx,float,double),数值会编译到代码中,作为立即数来使用;
  2)在代码中的数据的长度和类型相关;
  3)常量区得数据会受到系统内存属性的保护;
  4)const类型在编译时修改,会受到编译的检查;
  5)字符串常量放置在常量区,相同的字符串只存在一份

  水平很一般,错误难免,望多指教!

                                                      五边形  2011年5月

【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (14)
雪    币: 1410
活跃值: 活跃值 (94)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jldhwzm 活跃值 2011-5-27 05:35
2
0
好帖子!顶!
雪    币: 176
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rvnctu 活跃值 2011-6-16 00:42
3
0
mark一下,以后学习
雪    币: 49
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ththydee 活跃值 2011-6-16 08:01
4
0
收藏了  慢慢学习
雪    币: 18
活跃值: 活跃值 (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
andyguo 活跃值 2011-6-16 09:11
5
0
学习一下,我最近在学习C++
雪    币: 23
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
阿进 活跃值 2011-6-16 09:56
6
0
VC丢了好多年喽 要捡起来
雪    币: 143
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 活跃值 1 2011-6-16 13:00
7
0
我更新了一篇关于简单函数调用过程的大家可以看看,放到其他板块去了,欢迎多提宝贵意见
http://bbs.pediy.com/showthread.php?p=970359#post970359
雪    币: 345
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jacalhu 活跃值 2011-6-16 13:21
8
0
写得好,,,学习下。。。
雪    币: 4
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
EasyLYP 活跃值 2011-6-17 20:10
9
0
好好学习一下。
雪    币: 35
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
seefly 活跃值 2011-6-18 00:00
10
0
先顶一个标记一下,考试完了看···
雪    币: 3
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万象天引 活跃值 2011-6-18 16:14
11
0
看不懂    先收藏了 以后再来看
雪    币: 3
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhoumoruei 活跃值 2011-6-19 18:33
12
0
不错,学习了!

希望楼主多多分享!
雪    币: 143
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 活跃值 1 2011-6-19 18:43
13
0
基本数据类型,常量,变量,数组和简单函数调用过程这几个我粗略的写了一点,其他的给了论坛中已有的帖子,大家可以看看,之前很多写的都不错,我不擅长写东西。
有问题多搜搜,多交流吧!
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hacyx 活跃值 2011-6-20 13:25
14
0
学习学习····
雪    币: 31
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JoviLuo 活跃值 2011-6-29 15:50
15
0
本以为是简单的问题。
进来看了才发现不简单。
楼主做的研究真是够深的,佩服啊。
游客
登录 | 注册 方可回帖
返回