C和C++处理register关键字的一处差异
C++并不是完全兼容C语言的,上次提到的sizeof('a')等于几的问题就是一例。今天我在编码时又无意中发现了一处不同:
用register关键字修饰的变量,在C语言中是不可以用&操作符取地址的,这是我已有的经验。因为编译器如果接受了程序员的建议把变量存入寄存器,它是不存在虚拟地址的。但在C++中,用register修饰的变量可以用&操作符取地址,这是我在一段代码中发现的。如果程序中显式取了register变量的地址,编译器一定会将这个变量定义在内存中,而不会定义为寄存器变量。
我在C99(ISO/IEC 9899:1999)和ISO C++(ISO/IEC 14882:2003)标准中得到了确认,C和C++标准对register遇到&的处理确实有不同的明确定义。但为什么要这样定义?我只能从标准的字里行间猜测。K&R C1中如何描述register我尚未查证,K&R C2(ANSI C)中说明了“register variables are to be placed in machine registers ... but compilers are free to ignore the advice ”。但在C99和ISO C++中,措辞分别变成:“suggests that access to the object be as fast as possible”、“a hint to the implementation that the object so declared will be heavily used”,不再特别提及“machine registers”。可见历史上register关键字在强调尽可能地把变量保存到寄存器,而现在的register关键字不再强调具体手段,只是建议编译器通过各种可行的方式优化该变量的访问(不过很多编译器会忽略这一关键字,而采用自身的优化策略)。C99可能是为了保持对K&R C的兼容而不允许取地址操作;而C++也许是因为没有历史包袱才放宽了这个限制吧。猜测而已,希望知道内幕的朋友告诉我更精确的答案。





3条评论 关于 “C和C++处理register关键字的一处差异”
由 luguo 发表于2009-04-30
C99已经明确指出了啊!
The implementation may treat any register declaration simply as an auto declaration. However,
whether or not addressable storage is actually used, the address of any part of an object declared with
storage-class specifier register cannot be computed, either explicitly (by use of the unary &
operator as discussed in 6.5.3.2)
C++0x也说的够清楚了吧:
the hint
can be ignored and in most implementations it will be ignored if the address of the object is taken.
由 Jian Lin 发表于2009-04-30
是的,我看过标准,文中也引用了标准中的部分文字。C和C++中register的语义是明确且不同的。
我是想说,二者这种差异的原因是什么?C++在这个问题上为什么不与C兼容?
Stroustrup在《The Design and Evolution of C++》中提到“C++和ANSI C之间不应该存在无故的不兼容”,C++因此也背上了C的不少历史包袱。有的不兼容之处,如sizeof('a')等于几的问题,在很多文献中都说明了原因。但像register语义为什么不兼容?我暂时没有找到有文献说明明确的原因。
由 LOL LOL 发表于2009-06-05
我不明白你们为什么会认为这(就像C++放宽的许多其它限制一样)影响了兼容性。C++只要求能“向后兼容”C代码,即C代码可以方便地移植到C++下。而放宽限制不影响兼容性——使用register关键字的C代码可以在C++下正确编译通过(排除其他因素的干扰)。