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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4860788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:47:49  来源:igfitidea点击:

Why is address of char data not displayed?

c++coutmemory-address

提问by hrnt

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 ;
}

The output is:

输出是:

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

Why?

为什么?

Another interesting thing: if int, char, string is in public, then the output is

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

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

something_2 - somethingis always equal to 8. Why? (not 9)

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

回答by hrnt

When you are taking the address of b, you get char *. operator<<interprets that as a C string, and tries to print a character sequence instead of its address.

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

try cout << "address of char :" << (void *) &b << endlinstead.

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

[EDIT] Like Tomek commented, a more proper cast to use in this case is static_cast, which is a safer alternative. Here is a version that uses it instead of the C-style cast:

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

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

回答by CashCow

There are 2 questions:

有2个问题:

  • Why it does not print the address for the char:
  • 为什么它不打印字符的地址:

Printing pointers will print the address for the int*and the string*but will not print the contents for char*as there is a special overload in operator<<. If you want the address then use: static_cast<const void *>(&c);

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

  • Why the address difference between the intand the stringis 8
  • 为什么之间的地址差intstring8

On your platform sizeof(int)is 4and sizeof(char)is 1so you really should ask why 8not 5. The reason is that string is aligned on a 4-byte boundary. Machines work with words rather than bytes, and work faster if words are not therefore "split" a few bytes here and a few bytes there. This is called alignment

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

Your system probably aligns to 4-byte boundaries. If you had a 64-bit system with 64-bit integers the difference would be 16.

您的系统可能与 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)

(注意:64 位系统通常指的是指针的大小,而不是 int。因此,具有 4 字节 int 的 64 位系统仍然会有 8 的差异,因为 4+1 = 5 但四舍五入为 8 . 如果 sizeof(int) 为 8,则 8+1 = 9 但这四舍五入为 16)

回答by Tony Delroy

When you stream the address of a char to an ostream, it interprets that as being the address of the first character of an ASCIIZ "C-style" string, and tries to print the presumed string. You don't have a NUL terminator, so the output will keep trying to read from memory until it happens to find one or the OS shuts it down for trying to read from an invalid address. All the garbage it scans over will be sent to your output.

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

You can probably get it to display the address you want by casting it, as in (void*)&b.

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

Re the offsets into the structure: you observed the string is placed at offset 8. This is probably because you have 32-bit ints, then an 8-bit char, then the compiler chooses to insert 3 more 8-bit chars so that the string object will be aligned at a 32-bit word boundary. Many CPUs/memory-architectures need pointers, ints etc. to be on word-size boundaries to perform efficient operations on them, and would otherwise have to do many more operations to read and combine multiple values from memory before being able to use the values in an operation. Depending on your system, it may be that every class object needs to start on a word boundary, or it may be that std::stringin particular starts with a size_t, pointer or other type that requires such alignment.

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

回答by peoro

Because when you pass a char*to std::ostreamit will print the C-style (ie: char array, char*) string it points to.

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

Remember that "hello"is a char*.

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

回答by trojanfoe

The address of char is being treated as a nul-terminated string and is displaying the contents of that address, which is probably undefined, but in this case an empty string. If you cast the pointers to void *, you will get the results you desire.

char 的地址被视为以空字符结尾的字符串,并显示该地址的内容,这可能是未定义的,但在这种情况下是一个空字符串。如果您将指针投射到void *,您将得到您想要的结果。

The difference between something2 and something being 8 is due to aligned and ability of the compiler to decide for itself where in the stack the variables are declared.

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

回答by Eli Iser

For the second issue - the compiler by default will pad structure members. The default pad is to the sizeof(int), 4 bytes (on most architectures). This is why an intfollowed by a charwill take 8 bytes in the structure, so the stringmember is at offset 8.

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

To disable padding, use #pragma pack(x), where x is the pad size in bytes.

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

回答by Taranfx

Your syntax should be

你的语法应该是

cout << (void*) &b

回答by DS.

hrnt is right about the reason for the blank: &bhas type char*, and so gets printed as a string until the first zero byte. Presumably bis 0. If you set bto, 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.

hrnt 关于空白的原因是正确的:&b具有 type char*,因此被打印为字符串,直到第一个零字节。大概b是 0。如果你设置b为,比如说,'A',那么你应该期望打印输出是一个以 'A' 开头的字符串,并继续垃圾直到下一个零字节。用于static_cast<void*>(&b)将其打印为地址。

For your second question, &c - &iis 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 charfields after bwithout affecting the address &c.

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