Почему адрес данных 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
is8
на платформе 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-размер площадки в байтах.
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
.