针对typeid()的疑惑

wjlsmail 2010-08-12 11:54:05
大家好,代码如下:

        
const int & ival1 = 0;
const int * const pival = &ival1;
const int * const &rpival = &ival1;
cout << typeid(pival).name() << endl; // Output: int const * ??
cout << typeid(rpival).name() << endl; // Output: int const * ??
//pival++;


typeid(pival).name()
typeid(rpival).name()
和声明差距太大了啊,为什么会是这样的输出呢?

另外,
        
int i = 0;
int &ri = i;
cout << typeid(&ri).name() << endl; // int const *


我觉得 typeid(&ri).name(): int * const 更符合引用的语义,大家觉得呢?

不对的地方请大家指出,推荐文章也可以,多谢!
...全文
253 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
wjlsmail 2010-08-14
  • 打赏
  • 举报
回复
结贴,感谢各位参与。
wjlsmail 2010-08-14
  • 打赏
  • 举报
回复

[Quote=引用 14 楼 coldmooon 的回复:]
再看是不是常量。
想要改变引用的目标,我很想这么写:
&b = &c;
但是不行,编译器报错:left operand must be l-value。
定义一个int &b=a;
除了初始化有点特殊外,编译器是把b当做*pb来看的,那么&b就是&*pb
*,&,这对操作符看起来是可逆的其实不然,一个间接访问,一个取地址,使&b退……


#include "stdafx.h"

int main(int argc, char* argv[])
{
int a=1;
int &b=a;
int c=3;
printf("%d\n", b);
1[&c]=int(&c);
printf("%d\n", b);
return 0;
}



[/Quote]



#include "stdafx.h"

int main(int argc, char* argv[])
{
int a=1;
int &b=a;
int c=3;
printf("%d\n", b);
1[&c]=int(&c);
printf("%d\n", b);
return 0;
}



结果只能是相同的,说明是一个 const pointer,不过是怎么绕过编译器检查的?编译器怎么不能识别出这种修改企图呢?
zotin 2010-08-13
  • 打赏
  • 举报
回复

int i = 0;
int &ri = i;
cout << typeid(&ri).name() << endl; // int const *

这儿是不是写错了,输出应该是int *才对。

const int i = 0;
const int &ri = i;
cout << typeid(&ri).name() << endl;

这段代码输出的才是int const *

作为引用,它的类型和被应用的类型是一样的,所以&ri和&i是同一个类型。
而int const *中的 const修饰int,表示变量是常数。如果写成int * const,那么修饰的是*,表示指针是常数。
wjlsmail 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 patricxuqi 的回复:]
const int* 说明是指针的类型是const int,即专门用来指向类型是const int数据的内存单元,而不是用来指向类型是int的数据的内存单元。后面的const是说明指针本身是常量,与指针可以指向哪一种数据无关(即指针类型)。不知道这样说你明白吗。至于限定符,我是套用编译器上的说法。
[/Quote]

你的说法我明白,回头看看限定符的具体描述。

但还是不能消除我对引用的typeid()的疑惑。
       
int i = 0;
int &ri = i;
cout << typeid(&ri).name() << endl; // int const *



我觉得 typeid(&ri).name(): int * const 更符合引用的语义。


k80179279 2010-08-13
  • 打赏
  • 举报
回复
当不需要移植的时候。。这些东西是有用的。
[Quote=引用 9 楼 zzw_happy 的回复:]
typeid,exception都是鸡肋,没几个人用,移植性也不强。
搞不懂c++为什么要搞这些乱七八糟的东西。
[/Quote]
ColdMooon 2010-08-13
  • 打赏
  • 举报
回复
再看是不是常量。
想要改变引用的目标,我很想这么写:
&b = &c;
但是不行,编译器报错:left operand must be l-value。
定义一个int &b=a;
除了初始化有点特殊外,编译器是把b当做*pb来看的,那么&b就是&*pb
*,&,这对操作符看起来是可逆的其实不然,一个间接访问,一个取地址,使&b退化成了一个只有值,没有地址的“指针常量”。
前面说了,程序中保存的是pb,pb肯定存在于某个内存单元里,用常规的办法没法得到她。
用点怪异的办法呢?请看程序:
#include "stdafx.h"

int main(int argc, char* argv[])
{
int a=1;
int &b=a;
int c=3;
printf("%d\n", b);
1[&c]=int(&c);
printf("%d\n", b);
return 0;
}

你猜输出时啥?
我不说,想知道的自己试。
猜对了说明你对栈结构有点了解。
ColdMooon 2010-08-13
  • 打赏
  • 举报
回复
我写了一坨代码来验证
#include "stdafx.h"
int a;
int &b=a;

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.

return b;
}

看看编译器怎么做的?
;	COMDAT _$E1
_TEXT SEGMENT
_$E1 PROC NEAR ; COMDAT

; 6 : int &b=a;

push ebp
mov ebp, esp
sub esp, 64 ; 00000040H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-64]
mov ecx, 16 ; 00000010H
mov eax, -858993460 ; ccccccccH
rep stosd
mov DWORD PTR ?b@@3AAHA, OFFSET FLAT:?a@@3HA ; b, a
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
_$E1 ENDP
_TEXT ENDS
PUBLIC _WinMain@16
; COMDAT _WinMain@16
_TEXT SEGMENT
_WinMain@16 PROC NEAR ; COMDAT

; 12 : {

push ebp
mov ebp, esp
sub esp, 64 ; 00000040H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-64]
mov ecx, 16 ; 00000010H
mov eax, -858993460 ; ccccccccH
rep stosd

; 13 : // TODO: Place code here.
; 14 :
; 15 : return b;

mov eax, DWORD PTR ?b@@3AAHA ; b
mov eax, DWORD PTR [eax]

; 16 : }

pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 16 ; 00000010H
_WinMain@16 ENDP
_TEXT ENDS
END

挖靠,_$E1是什么玩意?
这个玩意煞有介事的保护栈帧,保护寄存器,制造隔离带,完了再恢复,结果有用的就一句
mov DWORD PTR ?b@@3AAHA, OFFSET FLAT:?a@@3HA ; b, a
可以看到,是把a的偏移放到b的内存单元里。
用c语言讲,就是int* pb = &a。
再看怎么使用它。
mov eax, DWORD PTR ?b@@3AAHA ; b
mov eax, DWORD PTR [eax]
用c语言讲,就是
eax = pb;
return *eax;

所以,编译器对待引用跟指针是完全一样的。
程序员用引用,是为了少打几个字,毕竟打“.”比“->”省事点。
wjlsmail 2010-08-13
  • 打赏
  • 举报
回复
算啦,不讨论了,我的意思是:
引用是变量别名,一但绑定就不能修改,类似于一个指针常量。如下代码:

int i = 0;
int &ri = i;

既然ri类似一个指针常量,那么翻译为一个 int * const 才比较恰当。

主要是不清楚编译器到底是如何实现一个引用的,是在全局数据区记录一个别名呢,还是转换为一个指针常量呢,或者还是别的,不过看来不像是转换为指针常量,那又是什么呢?这是发帖请教的重点。
patricxuqi 2010-08-12
  • 打赏
  • 举报
回复
星号后面的const只是说明指针本身的值是常量,即不能改变指针的值。前面const是说被指针指向的地址上的内容是不能改变的,即一个const int“类型”。后面的const只是指针本身的“限定符”,而不是“类型”。
hastings 2010-08-12
  • 打赏
  • 举报
回复
看见引用就头疼~~~~~
情愿用指针。
pengzhixi 2010-08-12
  • 打赏
  • 举报
回复
typeid(pival).name()
typeid(rpival).name()
一点都没错啊,这两个指针的类型就是const int*至于后面的是说指针本身的指向不可修改而
wing_0706 2010-08-12
  • 打赏
  • 举报
回复
int i = 0;
int &ri = i;
---------------------------------
引用第一次被 赋值绑定后就不能改变了。。
所以被解释成 int const * 吧。。
个人观点。。
olncy 2010-08-12
  • 打赏
  • 举报
回复
我C++白学了,竟不知道C++里有typeid这个内置类?求高手赐教
zzw_happy 2010-08-12
  • 打赏
  • 举报
回复
typeid,exception都是鸡肋,没几个人用,移植性也不强。
搞不懂c++为什么要搞这些乱七八糟的东西。
patricxuqi 2010-08-12
  • 打赏
  • 举报
回复
const int* 说明是指针的类型是const int,即专门用来指向类型是const int数据的内存单元,而不是用来指向类型是int的数据的内存单元。后面的const是说明指针本身是常量,与指针可以指向哪一种数据无关(即指针类型)。不知道这样说你明白吗。至于限定符,我是套用编译器上的说法。
wjlsmail 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 patricxuqi 的回复:]
星号后面的const只是说明指针本身的值是常量,即不能改变指针的值。前面const是说被指针指向的地址上的内容是不能改变的,即一个const int“类型”。后面的const只是指针本身的“限定符”,而不是“类型”。

"后面的const只是指针本身的“限定符”,而不是“类型”。"
[/Quote]

to patricxuqi:
这个说法有根据吗?标准上有“限定符”的描述吗?似乎也可以说的通,如 const int i 的类型就是 int, 那么如何去区别声明中的哪些const是类型描述,哪些const是限定符呢?
wjlsmail 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 pengzhixi 的回复:]
typeid(pival).name()
typeid(rpival).name()
一点都没错啊,这两个指针的类型就是const int*至于后面的是说指针本身的指向不可修改而
[/Quote]

但我觉得既然“指针本身的指向不可修改”,就说明该指针是一个指针常量,所以后面的const也是它的类型的一部分,所以对于pival,类型应该是 const int * const。

65,187

社区成员

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

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