C++ 为什么不显示字符数据的地址?

C++ 为什么不显示字符数据的地址?,c++,cout,memory-address,C++,Cout,Memory Address,为什么? 另一件有趣的事情:如果int、char、string是公共的,那么输出是 address of int : something address of char : // nothing, blank area, that is nothing displayed address of string : something 某物2——某物总是等于8。为什么?不是9,因为当您将char*传递给std::ostr

为什么?

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

         address of int    :  something
         address of char   :     // nothing, blank area, that is nothing displayed
         address of string :  something 
某物2——某物总是等于8。为什么?不是9,因为当您将char*传递给std::ostream时,它将打印它所指向的C样式ie:char数组char*字符串


记住,hello是一个字符*

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

您可能可以通过强制转换它来让它显示您想要的地址,如void*&b


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

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


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

对于第二个问题,编译器默认将填充结构成员。默认的pad是sizeofint,在大多数架构中为4字节。这就是为什么int后跟char将占用结构中的8个字节,因此字符串成员位于偏移量8处

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

您的语法应该是

cout << "address of char   :" << static_cast<void *>(&b) << endl;
有两个问题:

为什么不打印字符的地址:
打印指针将打印int*和string*的地址,但不会打印char*的内容,因为operator中有一个特殊重载hrnt关于空白的原因是正确的:&b具有类型char*,因此将作为字符串打印,直到第一个零字节。b大概是0。如果您将b设置为,比如说“A”,那么您应该期望打印输出是一个以“A”开头的字符串,并继续使用垃圾,直到下一个零字节。使用static_cast&b将其打印为地址


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

由于没有构造函数,是否会自动创建默认构造函数,从而将b=0设置为自动空终止?也+1@Muggen:上面的代码不完整,所以谁知道提供了什么构造函数。@Muggen:不,生成的默认构造函数不会为零初始化b。你必须明确地这样做;e、 g.作为临时地址的地址,与新地址比较,地址var=Address,在0x地址var{};我认为,需要进行双重检查,或者使用静态存储持续时间函数/名称空间/全局静态的Address对象。由于对齐要求,我怀疑在许多编译器上,打包只能将字符串的地址设置为5字节偏移量。数据对齐平台不是特定的吗?此外,AFAIK标准中不允许int为4字节。@Muggen-数据对齐确实是特定于平台的,但最常见的是sizeofint-本机CPU大小。在32位CPU上,这是4字节。@Christopher-偏移量不是5字节,而是3字节。整数是从地址0到3。字符应该是从4到5,而不是从4到7。最后字符串从8开始。@Eli:字符在字节4处。字节5到7是填充,而不是字符的一部分,根据定义,字符的大小为sizeofchar==1。我指的是相对于封闭对象开头的偏移量5。hello是一个常量字符[6]。@MSalters:否。它是字符[6],使用时在字符*中衰减。仅在
C,但是在C++中,它是const char〔6〕。有趣的是,尽管与C向后兼容,它仍然可以退化为char*。@hrnt:这在C++03中被弃用,在C++11中被完全删除。你能举例说明为什么静态_cast在这里是一个更安全的选择吗?我不明白在这里使用void*有什么害处。@VishalSharma如果你知道b是什么,这里就没有了。但是当C++不是你所想的,C++编译器会给你额外的安全性;一个C级演员会盲目地按照你说的去做,而没有真正的关心,这是不好的。这里的目标仅仅是灌输良好的实践,因为我还不知道怎么做cout@VishalSharma是的,避免C型强制转换是一种很好的做法。这种特殊情况下的行为将是相同的。在其他情况下,&可能被重载,因此您无法获取地址,或者您可能正在做一些与常量/易失性正确性有关的事情,或者,或者,或者
  ... int    :  something 
  ... char   :   
  ... string :  something_2
cout << "address of char   :" << static_cast<void *>(&b) << endl;
cout << (void*) &b