测试代码在下面,我把输出信息在注释中。我用的是gcc 4.8.5和Centos 7.2。
#include <iostream>
#include <cstdio>
class C
{
public:
void foo() {
printf("%p, %p\n", &C::c, &(C::c)); // output value is 0x4, 0x7ffc2e7f52e8
std::cout << &C::c << std::endl; // output value is 1
}
int a;
int c;
};
int main(void)
{
C co;
printf("%p\n", &C::c); // output value is 0x4
std::cout << &C::c << std::endl; // output value is 1
// printf("%p\n", &(C::c)); // compile error, invalid use of non-static data member 'C::c'
co.foo();
return 0;
}::运算符比&运算符具有更高的优先级。我认为&C::c等于&(C::c),但是输出不一样。他们为什么不一样?&(C::c)会导致main中的编译错误,而不是foo函数中的编译错误,为什么呢?&C::c的价值在printf和std::cout中是不同的,为什么呢?发布于 2018-10-23 03:04:33
C++对&操作符的两种操作数进行了区分,通常是lvalue,具体是(合格的)标识符。在&C::c中,&的操作数是一个限定标识符(即名称),而在&(C::c)中,操作数是一个通用表达式(因为(不能是名称的一部分)。
限定标识符表单有一个特例:如果它引用一个类的非静态成员(如您的C::c),则&返回一个称为“指向C成员的指针”的特殊值。见有关成员指针的更多信息,请参见。
在&(C::c)中没有特例。C::c通常被解析并失败,因为没有对象可以获取c成员。至少在main中是这样的;在C的方法(如您的foo)中,有一个隐式this对象,因此C::c实际上在那里表示this->c。
至于为什么printf和cout的输出是不同的:当您尝试用<<打印成员指针时,它被隐式转换为bool,如果它是空指针,则生成false,否则生成true。false被打印为0;true被打印为1。您的成员指针不是空的,所以您得到了1。这与普通指针不同,后者被隐式转换为void *并打印为地址,但成员指针不能转换为void *,因此operator<<唯一适用的重载是用于bool的重载。见ltlt#Notes。
注意,从技术上讲,printf调用具有未定义的行为。%p接受一个void *,您传递的是不同类型的指针。在正常函数调用中,从T *到void *的自动转换将启动,但是printf是一个变量参数函数,它不为其参数列表提供类型上下文,因此需要手动转换:
printf("%p\n", static_cast<void *>(&(C::c)));该标准的相关部分是expr.unary.op,,即:
一元
&运算符的结果是指向其操作数的指针。操作数应该是一个值或一个限定id.如果操作数是一个限定id,它用类型m命名某个类C的非静态成员或变体成员T,则结果类型为“指向T类型的类C成员的指针”,并且是指定C::m的实际值。否则,如果表达式的类型为T,则结果的类型为“指向T的指针”.
发布于 2018-10-23 02:48:10
表达式&C::c导致指向成员c的指针,而表达式&(C::c)则生成成员变量c的地址。您在输出中看到的区别是,std::cout包含一个bool隐式转换,它告诉您指针是否为空。
由于&C::c实际上不是空的,所以隐式地将值true或1转换为bool。
发布于 2018-10-23 03:18:14
Q1:,&的语法有特殊的含义,后面跟着一个无括号的限定-id。它的意思是形成一个指针到成员.此外,没有其他方法可以形成指针到成员.C++17 expr.unary.op/4介绍了这一点:
指向成员的指针只有在使用显式
&且其操作数是限定id而不是括在括号内时才会形成。[注意:也就是说,表达式&(qualified-id)(限定-id被括在括号中)并不构成“指向成员的指针”类型的表达式。合格的身份证明也不.
Q3:在编写printf("%p\n", &C::c);的两种情况下,&C::c都是指向成员的指针.%p格式说明符只用于void *,因此这会导致未定义的行为,并且程序输出没有意义。
代码cout << &C::c;通过operator<<(bool val)输出指针到成员,因为从指针到成员之间存在从指针到成员到bool的隐式转换(在所有情况下都有结果true ),请参见卷积. code /1。
有关如何打印指向成员的指针的进一步讨论,见这个答案。
Q2:代码&(C::c)并不像上面解释的那样形成指向成员的指针。
现在,代码C::c是在语法范畴id-表达式.(即限定-id和不合格-id)。id-表达式对其使用有一些限制,例如expr.prim.id/1:
表示类的非静态数据成员或非静态成员函数的id-表达式只能用于:
当我们在C::foo函数中时,应用第一个要点。代码与&c相同,但具有不必要的限定条件。它的类型为int *。您可以使用std::cout << &(C::c);输出该地址,这将显示一个内存地址,this->c的地址。
当我们使用main函数时,这三个要点都不适用,因此&(C::c)格式不正确。
https://stackoverflow.com/questions/52940237
复制相似问题