Переинтерпретировать приведенное значение зависит от компилятора - PullRequest
0 голосов
/ 17 января 2019

Для той же программы:

const char* s = "abcd";
auto x1 = reinterpret_cast<const int64_t*>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << *x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"

В gcc5 ( ссылка ): 139639660962401
В gcc8 ( ссылка ): 1684234849

  1. Почему значение зависит от версии компилятора?
  2. Каков тогда безопасный способ компилятора перейти от const char * к int64_t и обратно (как в этой задаче - не для реальных целочисленных строк, а для строки с другими символами)?

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Когда вы разыменовываете указатель int64_t, он читает после конца памяти, выделенной для строки, из которой вы отлили.Если вы измените длину строки как минимум на 8 байт, целочисленное значение станет стабильным.

const char* s = "abcdefg"; // plus null terminator
auto x1 = reinterpret_cast<const int64_t*>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << *x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"

Если вы хотите вместо этого сохранить указатель в целом числе, вы должны использовать intptr_t и оставить* как:

const char* s = "abcd";
auto x1 = reinterpret_cast<intptr_t>(s);
auto x2 = reinterpret_cast<const char*>(x1);
std::cout << x1 << std::endl;
std::cout << x2 << std::endl; // Always "abcd"
0 голосов
/ 17 января 2019

Исходя из того, что RemyLebeau указал в комментариях к вашему посту,

unsigned 5_byte_mask = 0xFFFFFFFFFF; std::cout << *x1 & 5_byte_mask << std::endl;

Должен быть разумный способ получить то же значение на машине с прямым порядком байтов любым компилятором. Это может быть UB по той или иной спецификации, но, с точки зрения компилятора, вы разыменовываете восемь байтов по действительному адресу, для которого вы инициализировали пять байтов, и маскируете оставшиеся байты, которые являются неинициализированными / ненужными данными.

0 голосов
/ 17 января 2019
  1. Почему значение зависит от версии компилятора?

Поведение не определено.

  1. Каков тогда безопасный способ компилятора перейти от const char * к int64_t и обратно

Несколько неясно, что вы подразумеваете под "переходом от const char * к int64_t". Основываясь на примере, я предполагаю, что вы хотите создать отображение из последовательности символов (не большей длины, чем подходит) в 64-разрядное целое число таким образом, чтобы его можно было преобразовать обратно, используя другой процесс - возможно, скомпилированный другим (версия) компилятор.

Сначала создайте объект int64_t, инициализируйте его нулем:

int64_t i = 0;

Получить длину строки

auto len = strlen(s);

Проверьте, подходит ли он

assert(len < sizeof i);

Скопируйте байты последовательности символов в целое число

memcpy(&i, s, len);

(Пока у целочисленного типа нет представлений ловушек) Поведение четко определено, и сгенерированное целое число будет одинаковым во всех версиях компилятора, пока порядковый номер процессора (и представление отрицательных чисел) остается неизменным.

Чтение строки символов назад не требует копирования, потому что char исключительно разрешено использовать псевдонимы всех других типов:

auto back = reinterpret_cast<char*>(&i);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...