Почему адрес данных char не отображается?

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)

8 ответов


когда вы берете адрес b, вы получаете char *. operator<< интерпретирует это как строку C и пытается напечатать последовательность символов вместо ее адреса.

попробовать .

[EDIT] как прокомментировал Томек, более правильный бросок для использования в этом случае -static_cast, который является более безопасной альтернативой. Вот версия, которая использует его вместо C-style cast:

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

есть 2 вопроса:

  • почему он не печатает адрес для char:

печать указателя печать на адрес int*и string* но не будет печатать содержание char* как есть специальная перегрузка в operator<<. Если вам нужен адрес, используйте:static_cast<const void *>(&c);

  • почему разница адресов между int и string is 8

на платформе sizeof(int) и 4 и sizeof(char) и 1 так что вы действительно должны спросить, почему 8 не 5. Причина в том, что строка выровнена по 4-байтовой границе. Машины работают со словами, а не с байтами, и работают быстрее, если слова не "разбиты" на несколько байтов здесь и несколько байтов там. Это называется трассы

ваша система, вероятно, выравнивается по 4-байтовым границам. Если у вас 64-битная система с 64-разрядными целыми числами разница будет 16.

(Примечание: 64-разрядная система обычно относится к размеру указателя, а не int. Таким образом, 64-разрядная система с 4-байтовым int по-прежнему будет иметь разницу 8 как 4+1 = 5, но округляет до 8. Если sizeof (int) равен 8, то 8+1 = 9, но это округляет до 16)


когда вы передаете адрес char в поток, он интерпретирует это как адрес первого символа строки ASCIIZ "C-style" и пытается напечатать предполагаемую строку. У вас нет Терминатора NUL, поэтому вывод будет продолжать пытаться читать из памяти, пока не найдет его или ОС не отключит его для чтения с недопустимого адреса. Весь мусор, который он сканирует, будет отправлен на ваш вывод.

вы, вероятно, можете получить его для отображения адрес вы хотите, бросив его, как в (void*)&b.

Re смещения в структуре: вы заметили, что строка помещается в смещение 8. Вероятно, это связано с тем, что у вас есть 32-битные ints, затем 8-битный char, затем компилятор выбирает вставку еще 3 8-битных символов, чтобы объект string был выровнен по 32-битной границе слова. Многие процессоры / архитектуры памяти нуждаются в указателях, ints и т. д. чтобы быть на границах размера слова для выполнения эффективных операций над ними, и в противном случае придется делать многие другие операции для чтения и объединения нескольких значений из памяти, прежде чем использовать значения в операции. В зависимости от вашей системы, может быть, каждый объект класса должен начинаться с границы слова, или это может быть std::string в частности, начинается с size_t, указателя или другого типа, который требует такого выравнивания.


потому что, когда вы проходите char* до std::ostream он будет печатать C-style (т. е. массив символов,char*) строка, на которую он указывает.

помните, что "hello" - это char*.


адрес char обрабатывается как строка с нулевым завершением и отображает содержимое этого адреса, которое, вероятно, не определено, но в этом случае пустая строка. Если вы бросаете указатели на void *, вы получите желаемые результаты.

разница между something2 и something 8 обусловлена выравниванием и способностью компилятора самостоятельно решать, где в стеке объявляются переменные.


для второй проблемы-компилятор по умолчанию будет заполнять элементы структуры. По умолчанию pad имеет значение sizeof(int), 4 байта (на большинстве архитектур). Вот почему int затем char займет 8 байт в структуре, поэтому string член находится на смещении 8.

чтобы отключить заполнение, используйте #pragma pack(x), где x-размер площадки в байтах.


ваш синтаксис должен быть

cout << (void*) &b

hrnt прав о причине пустого:&b типа char*, и поэтому печатается как строка до первого нулевого байта. Предположительно b равен 0. Если вы установите b чтобы, скажем, "A", тогда вы должны ожидать, что распечатка будет строкой, начинающейся с " A " и продолжающейся с мусора до следующего нулевого байта. Использовать static_cast<void*>(&b) чтобы напечатать его как адрес.

для вашего второго вопроса,&c - &i равно 8, потому что размер int равен 4, символ равен 1, и строка начинается на следующей 8-байтовой границе (вы, вероятно, находитесь в 64-битной системе). Каждый тип имеет определенное выравнивание, и C++ выравнивает поля в структуре в соответствии с ним, добавляя соответствующее дополнение. (Эмпирическое правило заключается в том, что примитивное поле размера N выровнено по кратному N.), В частности, вы можете добавить еще 3 char поля после b без влияния на адрес &c.