奇怪的const

概述

constc++中意味着“不可改变”,但在有些情况下我们可以“合法”地绕过编译器去修改一些const数据,比如const_cast就可以剥离一个对象的const属性。然而,我们这样做在多大程度上是“合理”的,却因不同的问题而论,也许一不小心,你就可能掉入陷阱之中。

以下问题,我只分析,不说话,请各位看官自己判断。

 

目标是一个常数

这件事源于在网上看到的一篇文章,其来源已经不可考,但大意是:就如下C++程序,其输出是什么:

void foo()
{
const int a = 1;
int* p = const_cast<int*>(&a);
*p = 2;
printf(" a= %d/n *p= %d/n &a= %x/n p= %x /n/n", a, *p, &a, p);
}

 

我在VC2008下的实测结果为:

a = 1
*p = 2
&a = 12ff6c
p = 12ff6c

 

好了,问题出现:明明p所指向的就是变量a,但为何打印其值时a!=*p

这并非是我用错了const_cast,也不是编译器进行了优化的问题。事实上,在各版本的VCg++下的运行结果均是如此。

以下是VC2008debug版本的汇编代码:

const int a = 1;
0041146E mov dword ptr [a],1
int* p = const_cast<int*>(&a);
00411475 lea eax,[a]
00411478 mov dword ptr [p],eax
*p = 2;
0041147B mov eax,dword ptr [p]
0041147E mov dword ptr [eax],2
printf(" a= %d/n *p= %d/n &a= %x/n p= %x /n/n", a, *p, &a, p);
00411484 mov esi,esp
00411486 mov eax,dword ptr [p]
00411489 push eax
0041148A lea ecx,[a]
0041148D push ecx
0041148E mov edx,dword ptr [p]
00411491 mov eax,dword ptr [edx]
00411493 push eax
00411494 push 1
00411496 push offset string " a=/t%d/n *p=/t%d/n &a=/t%x/n p=/t%x /n/n"... (415808h)
0041149B call dword ptr [__imp__printf (419318h)]

 

printf()的四个参数入栈过程中我们可以看出:指针p的确指向变量a了,而变量a处的数值也的确被改写成2了,问题是:当压入a的值的时候,编译器直接压入了其原始数值1

关键其实在于:const_cast所操作的目标是否为基础数据类型(char, int, float, double等),如果是类(或结构体)对象则又将是另一番情形

当修改字符串常量

这个问题最早见于一篇文章《Solmyr的小品文系列之一:字符串放在哪里?》,在这里我只不过转述一二。

代码如下:

void foo()
{
char* str1 = "watch";
const char* str2 = "watch";
char str3[] = "watch";

str1
[0] = 'm';

std
::cout<< str1 << std::endl << str2 << std::endl << str3 << std::endl;
}

 

VC6Release版本运行结果如下:

match
match
watch

VC2008Release版本运行结果如下:

watch
watch
watch

 

容易看出:这段代码的运行结果决定于编译器,因为我们改写了不应该被改写的常量数据。更根本的原因是:由于编译器优化,str1str2实际上指向的是同一份”watch”字符串

这还带出了另一件事:尽管str1的声明中不带const,但它所指向的字符串数据隐含是const类型的

注意:这段代码只有Release版本才能顺利执行,Debug版版本运行时会得到一个Access violation 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值