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)
答案 0 :(得分:78)
当您获取b的地址时,您会获得char *
。 operator<<
将其解释为C字符串,并尝试打印字符序列而不是其地址。
尝试cout << "address of char :" << (void *) &b << endl
。
[编辑]像Tomek评论的那样,在这种情况下使用的更合适的演员是static_cast
,这是一个更安全的选择。这是一个使用它而不是C风格的演员版本的版本:
cout << "address of char :" << static_cast<void *>(&b) << endl;
答案 1 :(得分:23)
有两个问题:
打印指针将打印int*
和string*
的地址,但不会打印char*
的内容,因为operator<<
中存在特殊重载。如果您想要地址,请使用:static_cast<const void *>(&c);
int
和string
之间的地址差异为8
在您的平台sizeof(int)
上4
而sizeof(char)
为1
,所以您真的应该问为什么8
不是5
。原因是字符串在4字节边界上对齐。机器使用单词而不是字节,并且如果单词因此不是“分割”在这里的几个字节和那里的几个字节,则工作得更快。这称为对齐
您的系统可能与4字节边界对齐。如果您的64位系统具有64位整数,则差异为16。
(注意:64位系统通常是指指针的大小,而不是int。因此,具有4字节int的64位系统仍然会有8的差异,因为4 + 1 = 5但是舍入如果sizeof(int)为8,则8 + 1 = 9,但最多为16)
答案 2 :(得分:13)
当您将char的地址流式传输到ostream时,它会将其解释为ASCIIZ“C-style”字符串的第一个字符的地址,并尝试打印假定的字符串。您没有NUL终结器,因此输出将继续尝试从内存中读取,直到找到一个或操作系统关闭它以尝试从无效地址读取。它扫描的所有垃圾都将被发送到您的输出。
您可以通过投射来显示所需的地址,例如(void*)&b
。
将偏移量重新组合到结构中:您观察到字符串位于偏移量8.这可能是因为您有32位整数,然后是8位字符,然后编译器选择再插入3个8位字符这样字符串对象将在32位字边界处对齐。许多CPU /内存架构需要指针,整数等在字大小的边界上对它们执行有效的操作,否则必须做更多的操作来从内存中读取和组合多个值,然后才能使用这些值在一次行动中。根据您的系统,可能每个类对象都需要从单词边界开始,或者可能是std::string
特别是以size_t,指针或其他需要这种对齐的类型开始。
答案 3 :(得分:10)
因为当你将char*
传递给std::ostream
时,它会打印出它指向的C风格(即:char数组,char*
)字符串。
请注意"hello"
是char*
。
答案 4 :(得分:4)
char的地址被视为以空字符结尾的字符串,并显示该地址的内容,该地址可能未定义,但在本例中为空字符串。如果你将指针投射到void *
,你将得到你想要的结果。
something2和8之间的区别是由于对齐和编译器决定自己在堆栈中声明变量的位置的能力。
答案 5 :(得分:2)
对于第二个问题 - 默认情况下编译器将填充结构成员。默认填充是sizeof(int)
,4个字节(在大多数体系结构上)。这就是int
后跟char
将在结构中占用8个字节的原因,因此string
成员的偏移量为8。
要禁用填充,请使用#pragma pack(x)
,其中x是以字节为单位的填充大小。
答案 6 :(得分:2)
您的语法应为
cout << (void*) &b
答案 7 :(得分:0)
hrnt关于空白的原因是正确的:&b
具有类型char*
,因此被打印为字符串直到第一个零字节。假设b
为0.如果将b
设置为'A',那么您应该期望打印输出为以“A”开头的字符串,并继续使用垃圾直到下一个零字节。使用static_cast<void*>(&b)
将其打印为地址。
对于你的第二个问题,&c - &i
是8,因为int的大小是4,char是1,字符串从下一个8字节边界开始(你可能是64位系统)。每种类型都有一个特定的对齐方式,C ++根据它对齐结构中的字段,适当地添加填充。 (经验法则是大小为N的原始字段与N的倍数对齐。)特别是,您可以在char
之后再添加3个b
字段,而不会影响地址&c