Копирование целого числа в буфер memcpy C ++ - PullRequest
4 голосов
/ 29 мая 2009

В принципе, я хотел бы сохранить адрес указателя в буфере. Не спрашивайте меня, почему

char * buff = "myBuff";
char * myData = (char*)malloc(sizeof(char*));
int addressOfArgTwo = (unsigned int)buff;
memcpy(myData, &addressOfArgTwo, sizeof(char*));

cout << "Int Val: " << addressOfArgTwo << endl;
cout << "Address in buffer:" << (unsigned int)*myData << endl;

Я не понимаю, почему вышеприведенный код не работает. Выводит:

Int Val: 4472832
Address in buffer:0

Когда Int Val и Address в Buffer должны совпадать. спасибо

Ответы [ 4 ]

8 голосов
/ 29 мая 2009

Вы разыменовываете char *, в результате чего получается char, а затем приводите этот 1-байтовый char к целому числу, а не ко всем 4 байтам адреса (если это 32-битная машина, 8 байтов на 64-битной) , 4472832 - это 444000 в шестнадцатеричном формате. На машине с прямым порядком байтов вы захватываете последние 00.

*((unsigned int*)myData)

должно привести к отображению правильного номера.

1 голос
/ 19 января 2010

Это вообще опасно:

 *((unsigned int*)myData)

Intel IA-32 (к которому привыкли все) поддерживает невыровненный доступ, но некоторые другие архитектуры этого не делают. Они требуют выравнивания переменных (8-битные данные на 1-байтовых границах, 16-битные данные на 2-байтовых границах и 32-битные данные на 4-байтовых границах). В архитектуре, которая требует выравнивания, не выровненный доступ будет либо возвращать поврежденные данные, либо выдавать исключение процессора. Я видел, что это вызывало ошибку в реальной жизни на прошлой работе, тонкую ошибку, которая приводила к повреждению файловой системы из-за драйвера диска, поставляемого с программным пакетом, который мы использовали (на встроенной платформе).

В этом изолированном случае вы можете видеть, что адрес myData получен из malloc (), что должно означать, что он соответствующим образом выровнен для всех типов указателей, но приведение меньшего указателя к большему указателю обычно опасная практика, если вы не не знаю, откуда взялся указатель.

Безопасный способ извлечь 32-разрядное целое число из произвольной ячейки памяти - объявить временное 32-разрядное целое число и выполнить его копирование, рассматривая исходную память как необработанный массив символов:

unsigned int GetUnalignedLittleEndianUInt32(void *address)
{
    unsigned char *uc_address = (unsigned char *)address;
    return (
        (uc_address[3] << 24) |
        (uc_address[2] << 16) |
        (uc_address[1] << 8) |
        uc_address[0]
    );
}

или в более общем случае (с некоторыми издержками вызова функции):

unsigned int GetUnalignedUInt32(void *address)
{
    unsigned int value;
    memcpy(&value, address, sizeof(value));
    return value;
}

, что на самом деле является противоположностью функции memcpy (), которую вы сделали, чтобы получить указатель там.

Хотя, обрабатывая указатель как int:

int addressOfArgTwo = (unsigned int)buff;

также опасно, если вы переходите между 32-битной и 64-битной архитектурами, как указал Майкл. Указатели не всегда являются 32-битными целыми числами. Подумайте об использовании typedef, который вы можете позже изменить. В Linux принято, что указатель должен быть того же размера, что и long. В Windows есть typedefs INT_PTR, UINT_PTR, LONG_PTR и ULONG_PTR.

Итак, я бы наконец предложил (в любом случае для Windows):

ULONG_PTR GetAddressAtAddress(void *address)
{
    ULONG_PTR value;
    memcpy(&value, address, sizeof(value));
    return value;
}
1 голос
/ 29 мая 2009

как сказал Майкл, эта строка должна быть

cout << "Address in buffer:" << *((unsigned int*)myData) << endl
1 голос
/ 29 мая 2009
Instead of (int)*myData, it should be *((int*)myData)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...