C++ 指向成员的指针:指针值代表什么?
我正在玩指向成员的指针,并决定实际打印指针的值。结果不是我所期望的C++ 指向成员的指针:指针值代表什么?,c++,pointers,C++,Pointers,我正在玩指向成员的指针,并决定实际打印指针的值。结果不是我所期望的 #include <iostream> struct ManyIntegers { int a,b,c,d; }; int main () { int ManyIntegers::* p; p = &ManyIntegers::a; std::cout << "p = &ManyIntegers::a = " << p <<
#include <iostream>
struct ManyIntegers {
int a,b,c,d;
};
int main () {
int ManyIntegers::* p;
p = &ManyIntegers::a;
std::cout << "p = &ManyIntegers::a = " << p << std::endl; // prints 1
p = &ManyIntegers::b;
std::cout << "p = &ManyIntegers::b = " << p << std::endl; // prints 1
p = &ManyIntegers::c;
std::cout << "p = &ManyIntegers::c = " << p << std::endl; // prints 1
p = &ManyIntegers::d;
std::cout << "p = &ManyIntegers::d = " << p << std::endl; // prints 1
return 0;
}
#包括
结构多整数{
INTA、b、c、d;
};
int main(){
int ManyIntegers::*p;
p=&ManyIntegers::a;
std::cout标准的ostream操作符p
实际上在对象中包含偏移量。打印它们分别打印隐式转换的bool
值true或false(如果它们确实包含或不包含偏移量)。转换是因为ostream
的插入成员没有任何点重载成员指针。没有重载的运算符成员指针不一定是一个数值,通常是一个结构或类似的东西。我不认为有办法从成员指针获取值,但即使有,我也不认为这有什么用处。正如大家所说的,ostream
没有适当的运算符下面是一个完全符合标准的实现,用于显示指向成员的指针的内存表示形式:
#include <iostream>
#include <iomanip>
template<int... I> struct index_tuple { using succ = index_tuple<I..., sizeof...(I)>; };
template<int I> struct indexer { using type = typename indexer<I - 1>::type::succ; };
template<> struct indexer<0> { using type = index_tuple<>; };
template<typename T> typename indexer<sizeof(T)>::type index(const T &) { return {}; }
template<typename T> class dumper {
unsigned char buf[sizeof(T)];
friend std::ostream &operator<<(std::ostream &os, const dumper &o) {
std::ios_base::fmtflags flags{os.flags()};
std::copy_n(o.buf, sizeof(T),
std::ostream_iterator<int>(os << std::hex << std::showbase, " "));
return os << std::setiosflags(flags);
}
template<int... I> dumper (const T &t, index_tuple<I...>):
buf{reinterpret_cast<const unsigned char *>(&t)[I]...} {}
public:
dumper(const T &t): dumper(t, index(t)) {}
};
template<typename T> dumper<T> dump(const T &t) { return {t}; }
struct ManyIntegers {
int a,b,c,d;
};
int main () {
std::cout << "p = &ManyIntegers::a = " << dump(&ManyIntegers::a) << std::endl;
std::cout << "p = &ManyIntegers::b = " << dump(&ManyIntegers::b) << std::endl;
std::cout << "p = &ManyIntegers::c = " << dump(&ManyIntegers::c) << std::endl;
std::cout << "p = &ManyIntegers::d = " << dump(&ManyIntegers::d) << std::endl;
}
好吧,如果我改为使用int*p=newint(5);
,那么std::cout重新解释cast(p)
@curvative我指的是指向不同类型的成员的指针,只是为了简洁起见跳过了它。很抱歉出现了冲突。这到底是为什么有4个向上投票?提供的解决方案不起作用!。这合法吗?我在标准中找不到任何允许使用重新解释\u cast
从指针到成员转换为inte的内容gral类型。我所知道的合法执行此操作的唯一方法是*重新解释\u cast(&p)
,其中未签名的
应替换为适当大小的整数类型。这是一种强大的“联合强制类型”,但我不确定是否存在保证至少与指向成员的指针大小相等的数字类型。@MagnusHoff没有保证的数字大小,但对于指向数据成员的指针,可以相当安全地假设大小将小于或等于大小\u t
,因为所需的唯一信息是e偏移量。另一方面,对于指向成员函数的指针,问题更为复杂,在64位计算机上,如果它们是16字节,并且比任何整数类型都长,我也不会感到惊讶。我喜欢它。我自己的实现一直使用类模板,带有函数模板,该模板返回类模板以受益于类型推断;这是一个mu实现相同目的的一种更简单的方法。请注意,只有当转储程序是临时的时,它才真正起作用;否则,如果您正在转储一个临时的,则会出现对象生命周期问题。(这在实践中不是一个问题,但如果您将此实例放入工具箱中,它是值得记录的。)未指定p
实际包含的内容。只指定在不同类型的表达式中使用p
的结果。(在最常用的实现技术中,p
包含偏移量+1,因此指向成员的空指针可以全部为0位。)我同意你的观点,虽然实际上大多数编译器都包含你所说的偏移量:),但不管怎样,ideone指向成员的空指针似乎将所有位都设置为1:@MagnusHoff这可能是我会采用的解决方案:-)。但这不是我在现有编译器中看到的解决方案(g++和VC++,我想:我知道我看过一两个,但我不再100%确定是哪一个)。我想这需要一些解释。你能用几句话解释一下你在那里做什么吗?@BjörnPollex我正在将成员的内存内容复制到一个无符号字符
缓冲区,以便将其打印出来。索引技巧只是为了高效地执行复制。
#include <cstddef>
#include <iostream>
struct Dumper {
unsigned char *p;
std::size_t size;
template<class T>
Dumper(const T& t) : p((unsigned char*)&t), size(sizeof t) { }
friend std::ostream& operator<<(std::ostream& os, const Dumper& d) {
for(std::size_t i = 0; i < d.size; i++) {
os << "0x" << std::hex << (unsigned int)d.p[i] << " ";
}
return os;
}
};
#include <iostream>
struct ManyIntegers {
int a,b,c,d;
};
int main () {
int ManyIntegers::* p;
p = &ManyIntegers::a;
std::cout << "p = &ManyIntegers::a = " << Dumper(p) << "\n";
p = &ManyIntegers::b;
std::cout << "p = &ManyIntegers::b = " << Dumper(p) << "\n";
p = &ManyIntegers::c;
std::cout << "p = &ManyIntegers::c = " << Dumper(p) << "\n";
p = &ManyIntegers::d;
std::cout << "p = &ManyIntegers::d = " << Dumper(p) << "\n";
return 0;
}
#include <iostream>
#include <iomanip>
template<int... I> struct index_tuple { using succ = index_tuple<I..., sizeof...(I)>; };
template<int I> struct indexer { using type = typename indexer<I - 1>::type::succ; };
template<> struct indexer<0> { using type = index_tuple<>; };
template<typename T> typename indexer<sizeof(T)>::type index(const T &) { return {}; }
template<typename T> class dumper {
unsigned char buf[sizeof(T)];
friend std::ostream &operator<<(std::ostream &os, const dumper &o) {
std::ios_base::fmtflags flags{os.flags()};
std::copy_n(o.buf, sizeof(T),
std::ostream_iterator<int>(os << std::hex << std::showbase, " "));
return os << std::setiosflags(flags);
}
template<int... I> dumper (const T &t, index_tuple<I...>):
buf{reinterpret_cast<const unsigned char *>(&t)[I]...} {}
public:
dumper(const T &t): dumper(t, index(t)) {}
};
template<typename T> dumper<T> dump(const T &t) { return {t}; }
struct ManyIntegers {
int a,b,c,d;
};
int main () {
std::cout << "p = &ManyIntegers::a = " << dump(&ManyIntegers::a) << std::endl;
std::cout << "p = &ManyIntegers::b = " << dump(&ManyIntegers::b) << std::endl;
std::cout << "p = &ManyIntegers::c = " << dump(&ManyIntegers::c) << std::endl;
std::cout << "p = &ManyIntegers::d = " << dump(&ManyIntegers::d) << std::endl;
}
p = &ManyIntegers::a = 0 0 0 0
p = &ManyIntegers::b = 0x4 0 0 0
p = &ManyIntegers::c = 0x8 0 0 0
p = &ManyIntegers::d = 0xc 0 0 0