为什么char数据的地址不显示?

class Address { int i ; char b; string c; public: void showMap ( void ) ; }; void Address :: showMap ( void ) { cout << "address of int :" << &i << endl ; cout << "address of char :" << &b << endl ; cout << "address of string :" << &c << endl ; } 

输出是:

  address of int : something address of char : // nothing, blank area, that is nothing displayed address of string : something 

为什么?

另一个有趣的事情:如果int,char,string是公开的,那么输出是

  ... int : something ... char : ... string : something_2 

something_2 - something总是等于8. 为什么? (不是9)

当你采取b的地址,你得到char *operator<<将其解释为Cstring,并尝试打印字符序列而不是地址。

请尝试cout << "address of char :" << (void *) &b << endl

[编辑]像Tomek评论说的,在这种情况下使用更合适的投射是static_cast ,这是一个更安全的select。 这是一个使用它的版本,而不是C风格的演员:

 cout << "address of char :" << static_cast<void *>(&b) << endl; 

有两个问题:

  • 为什么不打印char的地址:

打印指针将打印int*string*的地址,但会打印char*的内容,因为operator<<存在特殊的重载。 如果你想要的地址,然后使用: static_cast<const void *>(&c);

  • 为什么intstring之间的地址差异是8

在你的平台上, sizeof(int)4sizeof(char)1所以你应该问为什么8不是5 。 原因是string在一个4字节的边界上alignment。 机器使用的是单词而不是字节,如果单词不在这里“分裂”几个字节,而且在那里只有几个字节,则工作得更快。 这被称为alignment

您的系统可能alignment到4个字节的边界。 如果你有64位整数的64位系统,那么它们的差别就是16。

(注意:64位系统一般是指一个指针的大小,而不是一个int,所以一个具有4个字节的int的64位系统仍然会有一个8的差异,如4 + 1 = 5,但会舍入到8 。如果sizeof(int)是8,那么8 + 1 = 9,但是这个取整为16)

将string的地址stream式传输到ostream时,将其解释为ASCIIZ“C-style”string的第一个字符的地址,并尝试打印推测的string。 您没有NUL终止符,所以输出将不断尝试从内存中读取,直到碰巧find一个,或者操作系统将其closures以尝试从无效地址读取。 它扫描的所有垃圾将被发送到您的输出。

你可以通过强制转换来显示你想要的地址,例如(void*)&b

将偏移量复制到结构中:您观察到string被放置在偏移8处。这可能是因为您有32位整数,然后是8位字符,则编译器select插入3个8位字符,以便string对象将在32位字边界alignment。 许多CPU /存储器体系结构需要指针,整数等在字大小的边界上对其执行有效的操作,否则将不得不做更多的操作来读取和组合来自存储器的多个值,然后才能够使用值在操作中。 根据你的系统,可能每个类对象都需要从一个字边界开始,或者可能是std::string特别是以一个size_t,指针或其他需要这种alignment的types开始。

因为当你传递一个char*std::ostream它会打印它指向的C风格(即:char数组, char* )string。

请记住, "hello"是一个char*

char的地址被视为一个nul结尾的string,并显示该地址的内容,这可能是未定义的,但在这种情况下是一个空string。 如果你把指针指向void * ,你会得到你想要的结果。

something2和8之间的区别是由于编译器的alignment和能力决定自己在栈中声明variables的位置。

对于第二个问题 – 编译器默认会填充结构成员。 默认的pad是sizeof(int) ,4字节(在大多数体系结构上)。 这就是为什么一个int后跟一个char将需要8个字节的结构,所以string成员在偏移8。

要禁用填充,请使用#pragma pack(x) ,其中x是以字节为单位的填充大小。

你的语法应该是

 cout << (void*) &b 

hrnt是正确的关于空白的原因: &b有typeschar* ,所以被打印为一个string,直到第一个零字节。 假设b是0.如果你将b设置为'A',那么你应该期望打印输出是一个以'A'开头的string,并且继续下一个零字节。 使用static_cast<void*>(&b)将其作为地址打印。

对于第二个问题, &c - &i是8,因为int的大小是4,char是1,并且string从下一个8字节边界开始(可能是在64位系统上)。 每种types都有一个特定的alignment方式,C ++根据这个alignment结构中的字段,适当地添加填充。 (经验法则是大小为N的原始字段与N的倍数alignment。)特别是可以在b之后再添加3个char字段,而不会影响地址&c