为什么成员函数地址离自由函数这么远?
Why member function address are so far away from free functions?
以这个例子为例:https://godbolt.org/z/gHqCSA
#include<iostream>
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*p)(Args...) ) {
return os << (void*)p;
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*p)(Args...) )
{
unsigned char* internal_representation = reinterpret_cast<unsigned char*>(&p);
os << "0x" << std::hex;
for(int i = 0; i < sizeof p; i++) {
os << (int)internal_representation[i];
}
return os;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
}
// Prints:
// 0. 0x7018400100000000000
// 1. 0x100401080
// 2. 0x100401087
// 3. 0x100401093
我看到成员函数的地址是0x7018400100000000000
,这是可以理解的,因为成员函数指针有16个字节,而自由函数0x100401080
只有8个字节。
但是,为什么成员函数地址0x7018400100000000000
离自由函数地址0x100401080
那么远呢?即,|0x7018400100000000000 - 0x100401080| = 0x70184000FFEFFBFEF80
?
为什么它不更近,例如 0x100401...
而不是 0x701840...
?还是我打印成员函数地址错了?
您的架构是小端架构。地址的低字节在p
的第一个字节,所以你的地址是倒着打印出来的。
自动检测little/big字节序的固定代码:https://godbolt.org/z/XSvT5R
#include <iostream>
#include <iomanip>
#include <sstream>
inline bool is_big_endian() {
long int longvalue = 1;
//
unsigned char* representation = reinterpret_cast<unsigned char*>(&longvalue);
return ( (unsigned) representation[sizeof(long int) - 1] ) == 1;
}
template<typename Pointer>
std::ostream& print_pointer(std::ostream& os, const Pointer& pointer) {
const unsigned char* representation = (unsigned char*) &pointer;
int precision = 0;
bool haszeros = false;
unsigned firsthexdigit;
unsigned secondhexdigit;
std::ostringstream stream;
stream.flags( os.flags() );
stream << std::hex;
#define print_pointer_HEX_DIGIT \
firsthexdigit = (unsigned) representation[index] >> 4 & 0xf; \
secondhexdigit = (unsigned) representation[index] & 0xf; \
if( haszeros || firsthexdigit ) { \
precision++; \
haszeros = true ; \
stream << firsthexdigit; \
} \
if( haszeros || secondhexdigit ) { \
precision++; \
haszeros = true ; \
stream << secondhexdigit; \
}
if( is_big_endian() ) {
for(int index = 0; index < static_cast<int>(sizeof pointer); index++) {
print_pointer_HEX_DIGIT
}
}
else {
for(int index = static_cast<int>(sizeof pointer - 1); index >= 0 ; index--) {
print_pointer_HEX_DIGIT
}
}
if( os.precision() - ++precision > 0 ) {
return os << "0x" + std::string( os.precision() - ++precision, '0' ) + stream.str();
}
return os << "0x" + stream.str();
}
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
std::cout << "4. " << std::setfill('0') << std::setw(16) << fun_void_void << std::endl;
std::cout << "5. " << std::setprecision(16) << fun_void_double << std::endl;
}
// Prints:
// 0. 0x100402e80
// 1. 0x100401118
// 2. 0x10040111f
// 3. 0x10040112b
// 4. 000000x100401118
// 5. 0x0000010040111f
以这个例子为例:https://godbolt.org/z/gHqCSA
#include<iostream>
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*p)(Args...) ) {
return os << (void*)p;
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*p)(Args...) )
{
unsigned char* internal_representation = reinterpret_cast<unsigned char*>(&p);
os << "0x" << std::hex;
for(int i = 0; i < sizeof p; i++) {
os << (int)internal_representation[i];
}
return os;
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
}
// Prints:
// 0. 0x7018400100000000000
// 1. 0x100401080
// 2. 0x100401087
// 3. 0x100401093
我看到成员函数的地址是0x7018400100000000000
,这是可以理解的,因为成员函数指针有16个字节,而自由函数0x100401080
只有8个字节。
但是,为什么成员函数地址0x7018400100000000000
离自由函数地址0x100401080
那么远呢?即,|0x7018400100000000000 - 0x100401080| = 0x70184000FFEFFBFEF80
?
为什么它不更近,例如 0x100401...
而不是 0x701840...
?还是我打印成员函数地址错了?
您的架构是小端架构。地址的低字节在p
的第一个字节,所以你的地址是倒着打印出来的。
自动检测little/big字节序的固定代码:https://godbolt.org/z/XSvT5R
#include <iostream>
#include <iomanip>
#include <sstream>
inline bool is_big_endian() {
long int longvalue = 1;
//
unsigned char* representation = reinterpret_cast<unsigned char*>(&longvalue);
return ( (unsigned) representation[sizeof(long int) - 1] ) == 1;
}
template<typename Pointer>
std::ostream& print_pointer(std::ostream& os, const Pointer& pointer) {
const unsigned char* representation = (unsigned char*) &pointer;
int precision = 0;
bool haszeros = false;
unsigned firsthexdigit;
unsigned secondhexdigit;
std::ostringstream stream;
stream.flags( os.flags() );
stream << std::hex;
#define print_pointer_HEX_DIGIT \
firsthexdigit = (unsigned) representation[index] >> 4 & 0xf; \
secondhexdigit = (unsigned) representation[index] & 0xf; \
if( haszeros || firsthexdigit ) { \
precision++; \
haszeros = true ; \
stream << firsthexdigit; \
} \
if( haszeros || secondhexdigit ) { \
precision++; \
haszeros = true ; \
stream << secondhexdigit; \
}
if( is_big_endian() ) {
for(int index = 0; index < static_cast<int>(sizeof pointer); index++) {
print_pointer_HEX_DIGIT
}
}
else {
for(int index = static_cast<int>(sizeof pointer - 1); index >= 0 ; index--) {
print_pointer_HEX_DIGIT
}
}
if( os.precision() - ++precision > 0 ) {
return os << "0x" + std::string( os.precision() - ++precision, '0' ) + stream.str();
}
return os << "0x" + stream.str();
}
template<typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return(*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
template <typename ClassType, typename Return, typename... Args>
std::ostream& operator <<(std::ostream& os, Return (ClassType::*pointer)(Args...) ) {
return print_pointer(os , pointer);
}
struct test_debugger { void var() {} };
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}
int main() {
std::cout << "0. " << &test_debugger::var << std::endl;
std::cout << "1. " << fun_void_void << std::endl;
std::cout << "2. " << fun_void_double << std::endl;
std::cout << "3. " << fun_double_double << std::endl;
std::cout << "4. " << std::setfill('0') << std::setw(16) << fun_void_void << std::endl;
std::cout << "5. " << std::setprecision(16) << fun_void_double << std::endl;
}
// Prints:
// 0. 0x100402e80
// 1. 0x100401118
// 2. 0x10040111f
// 3. 0x10040112b
// 4. 000000x100401118
// 5. 0x0000010040111f