Почему адрес 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)
Ответы
Ответ 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
.