Использование reinterpret_cast для возврата long long из char*

У меня есть следующий код:

char* p = "12345";

long long x = *reinterpret_cast<long long*>(p);

и я продолжаю получать 228509037105 для x- Я ожидал 12345.

Что я делаю не так?

ОБНОВИТЬ:

Я задал вопрос неправильно из-за моего первоначального понимания. Однако из того, что мне позже сказали, можно прочитать 8 байтов из массива символов, используя reinterpret_cast! В конце концов, независимо от того, являются ли биты значением или указателем, на битовом уровне это одно и то же!


person user997112    schedule 22.07.2014    source источник
comment
reinterpret_cast работает совсем не так. См. справку.   -  person chris    schedule 22.07.2014
comment
@BaummitAugen: почти весь вопрос, почти ничего в тегах C и C++, хотя ...   -  person Deduplicator    schedule 22.07.2014


Ответы (3)


reinterpret_cast указателей заставляет компилятор переинтерпретировать адрес памяти в другом типе данных. Чтобы преобразовать строку "12345" в длинное длинное 12345, вам нужно преобразовать число:

#include <sstream>

long long str2ll(const char* p) {
    std::sstream ss;
    ss << p;
    long long r;
    ss >> r;
    return r;
}

Как говорит Крис в комментариях, в С++ 11 вы можете использовать std::stoll:

const char* p = "12345";
long long n = std::stoll(std::string(p));

Обновление: вы можете прочитать long long из 8 байтов памяти, но строка "12345678", интерпретированная как указатель long long, не будет целым числом "12345678", а зависит от порядок байтов вашей архитектуры:

const char* p = "12345678";
long long n = *reinterpret_cast<const long long*>(p);
std::cout << n << std::endl;

Эта программа печатает 4050765991979987505 или 3544952156018063160, независимо от того, используете ли вы архитектуру с обратным или обратным порядком байтов. И это потому, что:

hex(4050765991979987505) = 0x38 37 36 35 34 33 32 31
hex(3544952156018063160) = 0x31 32 33 34 35 36 37 38

0x38 — это шестнадцатеричное представление цифры ASCII 8.

person vz0    schedule 22.07.2014
comment
Хорошо, я немного ошибся в своем понимании и, следовательно, в том, как я задал вопрос, НО вы все равно можете использовать reinterpret_cast для чтения 8 байтов из char* (так мне сказали).... - person user997112; 22.07.2014
comment
@user997112 user997112 Конечно, вы можете прочитать 8 байтов с помощью reinterpret_cast, проблема в том, как вы их интерпретируете. я обновил свой ответ - person vz0; 22.07.2014

Вы неправильно понимаете использование reinterpret_cast. Пожалуйста, ознакомьтесь с этой страницей документации по reinterpret_cast.

Ваша функция делает следующее: Строка char* p = "12345"; создает переменную типа указатель на символ с именем p, которая указывает на область памяти, содержащую буфер констант, инициализированный 6 байтами \0x31\0x32\0x33\0x34\0x35\0x00. Когда вы передаете эту переменную p, например, в printf, она интерпретирует память, на которую указывает p, как строку с завершающим нулем и печатает «12345».

Строка long long x = *reinterpret_cast<long long*>(p); создает временный указатель на long-long, инициализированный значением p, что означает, что он указывает на ту же область памяти, что и p (на самом деле это поведение undefined, как в случае 6 в приведенной выше ссылке), затем разыменовывает его и присваивает значение x. Поскольку long long обычно имеет длину 8 байт, а p указывает только на 6 допустимых байтов, это разыменование снова является поведением undefined, но вы получаете 228509037105 (двоичный 0x3534333231), что означает, что ваша машина имеет обратный порядок байтов, а дополнительные 2 байта также равны 0. .

Если вы хотите получить x == 12345, правильный способ сделать это long long x = std::stoll(p).

Вы также неправильно понимаете тот факт, что «Однако из того, что мне позже сказали, можно прочитать 8 байтов из массива символов, используя reinterpret_cast». Что вы можете сделать, так это преобразовать значение char* в значение long long, предполагая, что sizeof void* не больше, чем sizeof(long long) на вашем компьютере (см. случай 2 в ссылке выше). Если sizeof void* равно 8, то вы «читаете 8 байтов из« массива символов »(фактически из указателя на символ): long long x = reinterpret_cast<long long>(p). Это дает вам адрес, который изначально содержал p, сохраненный как значение long long в переменной x Все, что вы делаете с этим значением, кроме приведения его обратно к char*, является неопределенным поведением.Вы можете сделать, например, printf(reinterpret_cast<char*>(x)), что напечатает исходный буфер символов "12345".

person axnsan    schedule 22.07.2014

Базовые байты 0x31, 0x32, 0x33, 0x34 and 0x35 для значений ascii 1,2,3,4 and 5. Возьмите полученное значение и преобразуйте его в шестнадцатеричный формат, и вы поймете, о чем я говорю.

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

person Vinbot    schedule 22.07.2014
comment
Вы бы использовали неявное преобразование из char * в void * и static_cast в обратном порядке. По своему опыту я использовал reinterpret_cast для таких вещей, как SetWindowLongPtr, где вы могли бы передавать указатель на что-то, что принимает целочисленный тип. - person chris; 22.07.2014