64
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 个)

4

8 回答 8

99

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

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

[编辑] 就像 Tomek 评论的那样,在这种情况下使用更合适的演员阵容是static_cast,这是一个更安全的选择。这是一个使用它而不是 C 样式转换的版本:

cout << "address of char   :" << static_cast<void *>(&b) << endl;
于 2011-02-01T09:21:42.263 回答
31

有2个问题:

  • 为什么它不打印字符的地址:

打印指针将打印 和 的地址,int*string*不会打印 的内容,char*因为 . 中有一个特殊的重载operator<<。如果您想要地址,请使用:static_cast<const void *>(&c);

  • int为什么the和the的地址不同string8

在你的平台sizeof(int)上是这样4,所以你真的应该问为什么不。原因是字符串在 4 字节边界上对齐。机器使用单词而不是字节工作,如果单词没有因此“分割”这里几个字节和那里几个字节,机器工作得更快。这称为对齐sizeof(char)185

您的系统可能与 4 字节边界对齐。如果您有一个具有 64 位整数的 64 位系统,则差异将是 16。

(Note: 64-bit system generally refers to the size of a pointer, not an int. So a 64-bit system with a 4-byte int would still have a difference of 8 as 4+1 = 5 but rounds up to 8. If sizeof(int) is 8 then 8+1 = 9 but this rounds up to 16)

于 2011-02-07T17:04:41.750 回答
14

当您将 char 的地址流式传输到 ostream 时,它会将其解释为 ASCIIZ“C 样式”字符串的第一个字符的地址,并尝试打印假定的字符串。您没有 NUL 终止符,因此输出将继续尝试从内存中读取,直到它碰巧找到一个或操作系统将其关闭以尝试从无效地址读取。它扫描的所有垃圾都将发送到您的输出。

您可能可以通过投射它来显示您想要的地址,如(void*)&b.

重新将偏移量放入结构中:您观察到字符串放置在偏移量 8 处。这可能是因为您有 32 位整数,然后是 8 位字符,然后编译器选择再插入 3 个 8 位字符,以便字符串对象将在 32 位字边界处对齐。许多 CPU/内存架构需要指针、整数等位于字大小边界上才能对其执行有效操作,否则必须执行更多操作才能从内存中读取和组合多个值,然后才能使用这些值在一次手术中。根据您的系统,可能每个类对象都需要从字边界开始,或者可能std::string特别以 size_t、指针或其他需要这种对齐的类型开始。

于 2011-02-01T09:22:07.763 回答
11

因为当您将 a 传递char*std::ostream它时,它将打印char*它指向的 C 样式(即:char 数组,)字符串。

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

于 2011-02-01T09:21:33.577 回答
4

char 的地址被视为以 nul 结尾的字符串并显示该地址的内容,该地址可能未定义,但在本例中为空字符串。如果您将指针投射到void *,您将获得所需的结果。

something2 和 something 为 8 之间的区别是由于对齐和编译器能够自行决定在堆栈中声明变量的位置。

于 2011-02-01T09:23:31.480 回答
2

对于第二个问题 - 默认情况下编译器将填充结构成员。默认填充为sizeof(int), 4 个字节(在大多数架构上)。这就是为什么 aint后跟 achar将在结构中占用 8 个字节,因此该string成员位于偏移量 8 处。

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

于 2011-02-01T09:25:24.100 回答
2

你的语法应该是

cout << (void*) &b
于 2011-02-01T10:24:44.217 回答
0

hrnt is right about the reason for the blank: &b has type char*, and so gets printed as a string until the first zero byte. Presumably b is 0. If you set b to, say, 'A', then you should expect the printout to be a string starting with 'A' and continuing with garbage until the next zero byte. Use static_cast<void*>(&b) to print it as a an address.

For your second question, &c - &i is 8, because the size of an int is 4, the char is 1, and the string starts at the next 8-byte boundary (you are probably on a 64-bit system). Each type has a particular alignment, and C++ aligns the fields in the struct according to it, adding padding appropriately. (The rule of thumb is that a primitive field of size N is aligned to a multiple of N.) In particular you can add 3 more char fields after b without affecting the address &c.

于 2011-02-13T20:31:27.330 回答