Подтвердить что ты не робот

Почему адрес 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, строка является общедоступной, то вывод

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

something_2 - something всегда равно 8. Почему? (не 9)

4b9b3361

Ответ 1

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

попробуйте cout << "address of char :" << (void *) &b << endl вместо этого.

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

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

Ответ 2

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

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

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

  • Почему разница адресов между int и string составляет 8

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Помните, что "hello" является char*.

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

cout << (void*) &b

Ответ 8

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

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