关于c ++:为什么char数据的地址没有显示?

Why is address of char data not displayed?

1
2
3
4
5
6
7
8
9
10
11
12
13
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 ;
}

输出是:

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

为什么?

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

1
2
3
  ... int    :  something
  ... char   :  
  ... string :  something_2

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


当你记下B的地址时,你就得到了1〔5〕。operator<<将其解释为C字符串,并尝试打印字符序列而不是其地址。

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

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

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


有两个问题:

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

打印指针将打印int*string*的地址,但不会打印char*的内容,因为operator<<中存在特殊过载。如果您需要地址,请使用:static_cast(&c);

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

在你的平台上,sizeof(int)4sizeof(char)1,所以你真的应该问为什么8不是5。原因是字符串在4字节边界上对齐。机器是用词而不是字节工作的,如果单词不是"分开"的,这里有几个字节和几个字节。这叫做对齐。

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

(注:64位系统通常指的是指针的大小,而不是int。因此,具有4字节int的64位系统仍有8的差异,如4 + 1=5,但舍入到8。如果SIZEOF(int)为8,则8 + 1=9,但此回合最多为16)。


当您将一个字符的地址传输到一个Ostream时,它将解释为asciiz"c-style"字符串的第一个字符的地址,并尝试打印假定的字符串。您没有nul终止符,因此输出将一直尝试从内存中读取,直到它恰好找到一个终止符,或者操作系统因为尝试从无效地址读取而关闭它。它扫描的所有垃圾都将发送到输出。

你可以通过投射它来让它显示你想要的地址,就像在(void*)&b中那样。

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


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

记住,"hello"char*


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

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


您的语法应该是

1
cout << (void*) &b


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

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


HRNT对空白的原因是正确的:EDCOX1〔0〕具有EDCOX1型(1),因此被打印为字符串,直到第一个零字节。推测b为0。如果设置EDOCX1,2,to,例如,"A",那么你应该期望打印输出是一个从"A"开始的字符串,然后继续到下一个零字节。使用EDCOX1×4来打印它作为一个地址。

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