const_cast的疑惑<在线!!>

baifanmvp 2008-12-13 05:30:02
为什么ic和*pc的值不一样,他们2个的地址我检查过了,是一模一样的,为什么一个地址输出2个不同的值?

#include <stdio.h>
int main(int argc, char* argv[])

{

const int ic = 100;

const int *pc=⁣

const_cast<int &>(ic)++;

printf("%d,%d\n", ic, *pc);

return 0;

}

...全文
257 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
lann64 2008-12-15
  • 打赏
  • 举报
回复
#include <stdio.h>
int main(int argc, char* argv[])

{

volatile const int ic = 100;

volatile const int *pc=⁣

const_cast<int &>(ic)++;

printf("%d,%d\n", ic, *pc);

return 0;

}

zhangyong369 2008-12-14
  • 打赏
  • 举报
回复
常量折叠
就呆在云上 2008-12-14
  • 打赏
  • 举报
回复
而且:

在c中const的意思是“一个不能被改变的普通变量“,在c中它总是占用存储空间而且它的名字是全局符。
c++编译器通常并不为const分配空间,它把这个定义保存在符号表中。当const常量被使用时,编译的时候就进行常量折叠。
就呆在云上 2008-12-14
  • 打赏
  • 举报
回复

在程序编译期间在可能的情况下符号常量的值会代替该名字的出现,这个替代过程,被称为常量折叠(constant folding)

To understand the behavior of C and C++ programs, you need to know about linkage. In an executing program, an identifier is represented by storage in memory that holds a variable or a compiled function body. Linkage describes this storage as it is seen by the linker. There are two types of linkage: internal linkage and external linkage.

Internal linkage means that storage is created to represent the identifier only for the file being compiled. Other files may use the same identifier name with internal linkage, or for a global variable, and no conflicts will be found by the linker – separate storage is created for each identifier. Internal linkage is specified by the keyword static in C and C++.

External linkage means that a single piece of storage is created to represent the identifier for all files being compiled. The storage is created once, and the linker must resolve all other references to that storage. Global variables and function names have external linkage. These are accessed from other files by declaring them with the keyword extern. Variables defined outside all functions (with the exception of const in C++) and function definitions default to external linkage. You can specifically force them to have internal linkage using the static keyword. You can explicitly state that an identifier has external linkage by defining it with the extern keyword. Defining a variable or function with extern is not necessary in C, but it is sometimes necessary for const in C++.

(对于C++来说,是global namespace的全局变量)C++默认const变量的链接性质是内部的,而C则相反,默认是外部的.在C++中,const变量默认是内部链接的,除非你显式加上extern修饰词,否则,其它文件是看不到的。


声明(declaration)引入一个名字,而定义(definition)给出程序中各个实体(entity,比如函数,类型等)的完整唯一的描述。

一个声明就是一个定义,除非:
1. 它声明了一个函数但是没有给出函数体。
2. 它使用了extern关键字。
3. 它声明了一个类的名字。
4. 它是typedef。
5. 它在类定义中声明了static members.


为什么类的静态变量不可以就地初始化(只能声明,不能定义):
在C++里,头文件定义一个const对象会怎么样:
一般不会怎么样,这个和C里的在头文件里定义const int一样,每一个包含了这个头文件的编译单元都会定义这个对象。但由于该对象是const的,所以没什么影响。但是:有2种情况可能破坏这个局面:
1.如果涉及到对这个const对象取地址并且依赖于这个地址的唯一性,那么在不同的编译单元里,取到的地址可以不同。(但一般很少这么做)
2.如果这个对象具有mutable的变量,某个编译单元对其进行修改,则同样不会影响到别的编译单元。

为什么类的静态常量也不可以就地初始化:
因为这相当于在头文件里定义了const对象。作为例外,int/char等可以进行就地初始化,是因为这些变量可以直接被优化为立即数(常量折叠),就和宏一样。

还有,头文件不应该含有非inline 函数或对象的定义。这些定义如果在同一程序的两个或多个文件中被包含就会产生重复定义的编译错误。


常量折叠的标准说法
e_sharp 2008-12-13
  • 打赏
  • 举报
回复
常量折叠
就呆在云上 2008-12-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 zmlovelx 的回复:]
Assembly code
12: const int ic = 100;
00401028 mov dword ptr [ebp-4],64h
13:
14: const int *pc=⁣
0040102F lea eax,[ebp-4]
00401032 mov dword ptr [ebp-8],eax
15:
16: const_cast<int &>(ic)++;
00401035 mov ecx,dword ptr [ebp-4]
00401038 add ecx,1
0040103B mov dword ptr [ebp-4],ecx
17:
18: printf(…
[/Quote]

11楼正解,呵呵,受教
cwei_hu 2008-12-13
  • 打赏
  • 举报
回复
c++中 编译器不会为一般的const常量分配内存空间, 而是将它们存放符号表中.
如果取了这个常量的地址,那么编译器将为此常量分配一个内存空间,生成一个常量副本,
所有通过地址对常量的操作都是针对副本
常量折叠,又叫常量替换,c++编译器会在编译时,将const常量的字面值保存在符号表中,在编译时使
用这个字面常量进行替换。


11楼说的很不错,好好看看吧
ypb362148418 2008-12-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 fengxuxing 的回复:]
首先来看一个例子:

int main(int argc, char* argv[])
{
const int i=0;
int *j = (int *) &i;
*j=1;
cout < <&i < <endlcout < <j < <endl;
cout < <i < <endl;
cout < <*j < <endl;
return 0;
}

结果是

0012ff7c
0012ff7c

0

1


因为i和j都指向相同的内存地址,所以输出的前两个结果是相同的,但为什么相同的内存里的结果不相同么?--这就是常量折叠.

这个"常量折叠"是 …
[/Quote]



支持!!!

const_cast的用法::
用法:const_cast<type_id> (expression)
  该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
  常量指针被转化成非常量指针,并且仍然指向原来的对象;
  常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
  Voiatile和const类试。举如下一例:
  class B{
  public:
  int m_iNum;
  }
  void foo(){
  const B b1;
  b1.m_iNum = 100; //comile error
  B b2 = const_cast<B>(b1);
  b2. m_iNum = 200; //fine
  }
  上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;
  使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。
帅得不敢出门 2008-12-13
  • 打赏
  • 举报
回复

12: const int ic = 100;
00401028 mov dword ptr [ebp-4],64h
13:
14: const int *pc=⁣
0040102F lea eax,[ebp-4]
00401032 mov dword ptr [ebp-8],eax
15:
16: const_cast<int &>(ic)++;
00401035 mov ecx,dword ptr [ebp-4]
00401038 add ecx,1
0040103B mov dword ptr [ebp-4],ecx
17:
18: printf("%d,%d\n", ic, *pc);
0040103E mov esi,esp
00401040 mov edx,dword ptr [ebp-8]
00401043 mov eax,dword ptr [edx]
00401045 push eax //这里是101入栈
00401046 push 64h //这里直接是100入栈了.
00401048 push offset string "%d,%d\n" (0041301c)
0040104D call dword ptr [__imp__printf (004150a4)]
00401053 add esp,0Ch
00401056 cmp esi,esp
00401058 call _chkesp (0040108e)
19:
20: return 0;
0040105D xor eax,eax

c++中 编译器不会为一般的const常量分配内存空间, 而是将它们存放符号表中.
如果取了这个常量的地址,那么编译器将为此常量分配一个内存空间,生成一个常量副本,
所有通过地址对常量的操作都是针对副本
常量折叠,又叫常量替换,c++编译器会在编译时,将const常量的字面值保存在符号表中,在编译时使
用这个字面常量进行替换。
机智的呆呆 2008-12-13
  • 打赏
  • 举报
回复

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
volatile int const ic = 100;//不加volatile,此时const ic被替换成了100
const int *pc=(const int *)⁣
const_cast<int &>(ic)++;
printf("%d,%d\n", ic, *pc);
system("pause");
return 0;

}
lc19890326 2008-12-13
  • 打赏
  • 举报
回复
学习
Qlaiaqu 2008-12-13
  • 打赏
  • 举报
回复
首先来看一个例子:

int main(int argc, char* argv[])
{
const int i=0;
int *j = (int *) &i;
*j=1;
cout<<&i<<endlcout<<j<<endl;
cout<<i<<endl;
cout<<*j<<endl;
return 0;
}

结果是

0012ff7c
0012ff7c

0

1


因为i和j都指向相同的内存地址,所以输出的前两个结果是相同的,但为什么相同的内存里的结果不相同么?--这就是常量折叠.

这个"常量折叠"是 就是在编译器进行语法分析的时候,将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。
我只是改了这个地址内容,但是i还是0,

因为编译器在优化的过程中,会把碰见的const全部以内容替换掉(跟宏似的: #define PI 3.1415,用到PI时就用3.1415代替),这个出现在预编译阶段;但是在运行阶段,它的内存里存的东西确实改变了!!!

lann64 2008-12-13
  • 打赏
  • 举报
回复
常量折叠
Vegertar 2008-12-13
  • 打赏
  • 举报
回复
简单说就是ic不在内存中,仅仅是一个符号.取地址时分配了内存,同时初始化了ic对应的数值.使用指针改变只是改变了这块内存中的数据,它与ic没有联系.
baifanmvp 2008-12-13
  • 打赏
  • 举报
回复

懂了
baifanmvp 2008-12-13
  • 打赏
  • 举报
回复
额。。。看的不太明白,能再清楚点么,谢谢
Vegertar 2008-12-13
  • 打赏
  • 举报
回复

#include <stdio.h>
int main(int argc, char* argv[])

{

const int ic = 100; // 编译期间的常量,没有地址,类似于C中的#define

const int *pc=⁣ // 分配内存.

const_cast<int &>(ic)++;

printf("%d,%d\n", ic, *pc); // ic仍然保存在符号表中,取数时使用的文本替换.

return 0;

}

Vegertar 2008-12-13
  • 打赏
  • 举报
回复

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧