2013-11-19 2 views
0
struct myStruct 
{ 
    int foo; 
} 

myStruct bar; 
bar.foo = 123; 
cout<<(char *) &bar<<endl; 

В заявлении cout выдается '{'. ASCII of 123 на самом деле '{' (bar.foo = 123. Изменение этого значения при печати разных символов). Что я не понимаю, так это то, чтоConfused by (char *) cast

cout<<(char *) &bar<<endl; 

должен технически распечатать адрес строки. Как я могу получить доступ к данным внутри структуры с помощью (char *) cast? Использование (int *) по-прежнему возвращает адрес. Я знаю, что (char *) заставляет данные упорядочиваться побайтовым образом, но разве это не должно влиять на адрес?

+1

'std :: cout' обрабатывает' char * 'как строку с нулевым символом и печатает как таковой. 'bar :: foo' адрес равен самому адресу bar. Поэтому вы печатаете 'bar :: foo', как будто это строка с нулевым завершением. Заметьте, он будет печатать до '\ 0', поэтому он может пройти мимо' bar :: foo', в зависимости от его значения. – lapk

+1

Вам повезло, что нет сбоя, потому что он читает память до первого «\ 0» ... Нет гарантии, что у вас есть один доступ к запрещенной зоне. – Johan

ответ

4

Существует перегрузка для <<, принимающая const char *, которая интерпретирует операнд как указатель на строку с нулевым символом C-стиля. Это перегрузка используется, например

cout << "Hello\n"; 

Если, как здесь, вы даете ему указатель на что-то другое, чем строка C-стиле, вы получите неопределенное поведение. На практике он будет печатать содержимое байта памяти байтом до тех пор, пока он не достигнет нулевого байта или не покинет конец читаемой памяти.

+0

Итак, если бы я отправил листинг над сокетом, скажите char * bytes = (char *) &bar; write (socketFD, bytes, sizeof (myStruct)); Это будет работать, учитывая, что порядок байтов одинаковый с обоих концов? –

+0

@AamirKhan: Да (предполагая, как вы говорите, совместимую макет памяти на обоих концах). Но литье бессмысленно: 'write' принимает' const void * ', а' & bar' будет конвертировать неявно, если вы будете писать (fd, & bar, sizeof bar) ' –

+0

Ahh да, конечно. Спасибо. –

2

<< на char* рассматривает его как строку C, а не указатель. Эта программа интерпретирует myStruct в качестве буфера sizeof(myStruct) байт и полагается на контенту, чтобы гарантировать, что она завершена NUL.

Чтобы распечатать адрес, просто пройдите &bar без литья.

+0

указатель здесь 'myStruct *', а не 'void *' – Wolf

+0

@Wolf: я хотел сказать, что его можно было бы отличить от 'void *', чтобы напечатать значение указателя, хотя здесь здесь не нужно. –

+0

А я вижу, извините за суету. – Wolf

1

Поскольку bar является объектом структуры myStruct, его начальный адрес и начальный адрес первого члена в myStruct, то есть bar.foo будет таким же. Итак, строка & даст вам начальный адрес объекта bar, а char * предоставит вам значение первого байта в этом адресе.

1

в отличии от int *, char * являются особым родом указателей, они также используется, чтобы указать на ASCII строки, как например:

const char * s = "hello world";

Для выражения (char *) &bar результата является char * указателем, cout поэтому будет печатать строка, потому что у нее есть специальный оператор для char *, который выводит строки. для int * нет оператора, существует только общий оператор для указателей, который печатает только адреса.

1

std::ostream обычно имеет перегрузку для operator << с const char *, к которому будет привязан char *.

Эта перегрузка рассматривает свой аргумент как строку символов ASCII с нулевым завершением.

1

Если вам нужно для вывода содержимого MyStruct в выходной поток, вам нужно определить ostream < < оператора для вашей структуры, как это:

std::ostream& operator <<(std::ostream& os, const myStruct& ms) 
{ 
    os << "myStruct { foo: " << ms.foo << "\n}"; 
    return os; 
} 

(символ *) ничего не изменить. Структура хранится в памяти как 4 байта = sizeof (int) или 8 байтов на 64-битном процессоре, в зависимости от архитектуры процессора в малой или большой форме (см. http://en.wikipedia.org/wiki/Endianness).

Ваш код, вероятно, работает на архитектуре архитектуры x86, поэтому младший байт хранится на нижнем адресе. Например, номер 123 в foo будет сохранен в виде байтов 7B 00 00 00. В памяти. Ваш cast co char * сообщит компилятору использовать оператор ostream для массива char *, который используется как строка в C. Каждый байт интерпретируется как один символ, заканчивается на 0 байт. Байт 123 соответствует символу ASCII '{', он заканчивается байтом 00, поэтому ваш код не будет разбиваться в этом случае. Другие значения могут привести к сбою вашего кода или печати байтов в стеке за пределами хранилища вашей структуры (до тех пор, пока не будет обнаружен нулевой байт или не сбой).

Надеюсь, это поможет.

0

На самом деле ваш код печатает адрес переменной struct bar, а не значение foo. (Char *) & bar преобразует адрес типа struct в (char *), означает c string type. Некоторые параметры функции c, C++ принимают тип struct как аргументы, поэтому нам нужно преобразовать тип struct в (char *) или (void *) в соответствии с параметрами функции.