C语言字符常量 xah,[原创]C语言-常量

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

上一篇 关于基本数据类型和局部变量链接:

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;

593949bae5956a837e21c0e29be0105e.png

因为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

4b22fcfed8d6e5ace584d620d8cfd8e6.png

在调试状态,直接修改内存

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月

上传的附件:

const异常.PNG

(15.71kb,279次下载)

修改字符串常量异常.PNG

(15.08kb,278次下载)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值