Подтвердить что ты не робот

Когда и как разрешено преобразование в char?

Мы можем посмотреть на представление объекта типа T путем преобразования a T*, который указывает на этот объект в char*. По крайней мере, на практике:

int x = 511;
unsigned char* cp = (unsigned char*)&x;
std::cout << std::hex << std::setfill('0');
for (int i = 0; i < sizeof(int); i++) {
  std::cout << std::setw(2) << (int)cp[i] << ' ';
}

Это выводит представление 511 в моей системе: ff 01 00 00.

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

4b9b3361

Ответ 1

Какое из приводов позволяет мне преобразовать int* в unsigned char*?

Этот C-стиль в этом случае совпадает с reinterpret_cast<unsigned char*>.

Можно ли использовать любой тип T * следующим образом?

Да и нет. Часть да. Вы можете безопасно использовать любой тип указателя в char* или unsigned char* (с соответствующими квалификаторами const и/или volatile). Результат определяется реализацией, но он легален.

Нет части: стандарт явно допускает char* и unsigned char* в качестве целевого типа. Однако вы не можете (например) безопасно применить double* к int*. Сделайте это, и вы пересекли границу от поведения, определенного при реализации, до поведения undefined. Это нарушает правило строгого сглаживания.

Ответ 2

Ваши литые карты:

unsigned char* cp = reinterpret_cast<unsigned char*>(&x);

Основное представление int определяется реализацией, и просмотр его в виде символов позволяет вам изучить это. В вашем случае это 32-битный маленький endian.

Здесь нет ничего особенного - этот метод проверки внутреннего представления действителен для любого типа данных.

С++ 03 5.2.10.7: Указатель на объект может быть явно преобразован в указатель на объект другого типа. За исключением того, что преобразование rvalue типа "указатель на T1" в тип "указатель на T2" (где T1 и T2 являются типами объектов и где требования к выравниванию T2 не более строгие, чем требования T1) и обратно к исходному типу исходное значение указателя, результат такого преобразования указателя не указан.

Это говорит о том, что приведение приводит к неопределенному поведению. Но прагматично говоря, кастинг от любого типа указателя до char* всегда позволит вам изучить (и изменить) внутреннее представление ссылочного объекта.

Ответ 3

Приведение в стиле C в этом случае эквивалентно reinterpret_cast. Стандарт описывает семантику в 5.2.10. В частности, в пункте 7:

"Указатель на объект может быть явно преобразован в указатель на другой тип объекта .70 Когда prvalue v типа" указатель на T1 "является преобразованный в тип" указатель на cvT2 ", результатом является static_cast<cvT2*>(static_cast<cvvoid*>(v)), если оба T1 и T2 равны стандартными форматами (3.9) и требованиями к выравниванию T2 являются не более строгие, чем у T1. Преобразование указателя типа" указатель на T1 "к типу" указатель на T2 "(где T1 и T2 являются типами объектов и где требования к выравниванию T2 не являются строгими, чем требования к T1) и обратно к исходному типу дает исходное значение указателя. Результат любого другого такого преобразования указателя не указан."

Что это означает в вашем случае, требования к выравниванию удовлетворяются, и результат не указан.

Ответ 4

Поведение реализации в вашем примере - это атрибут endianness вашей системы, в этом случае ваш процессор немного ориентирован.
О типе casting, когда вы отбрасываете int* в char*, все, что вы делаете, говорит компилятору интерпретировать, что cp указывает как char, поэтому он будет читать только первый байт и интерпретировать это как символ.

Ответ 5

Передача между указателями сама по себе всегда возможна, поскольку все указатели - это не что иное, как адреса памяти, и любой тип в памяти всегда можно рассматривать как последовательность байтов.

Но, конечно, способ формирования последовательности зависит от того, как представленный тип разбиения представлен в памяти, и что из объема спецификаций С++.

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

В общем, одна вещь, которую следует избегать, заключается в том, чтобы выразить соотношение между размерами типа как "предопределенное": в вашем примере вы принимаете sizeof(int) == 4*sizeof(char): это необязательно всегда верно.

Но всегда верно, что sizeof (T) = N * sizeof (char), следовательно, любой T всегда можно рассматривать как целое число char -s

Ответ 6

Если у вас нет оператора трансляции, то актер просто говорит "видеть" эту область памяти по-другому. Я бы сказал, ничего фантастического.

Затем вы читаете побайтовые области памяти; до тех пор, пока вы его не меняете, все нормально. Разумеется, результат того, что вы видите, сильно зависит от платформы: подумайте о контенте, размере слова, дополнении и т.д.

Ответ 7

Просто измените порядок байтов, затем он станет

00 00 01 ff

Что такое 256 (01) + 255 (ff) = 511

Это потому, что ваш плафом немного велик.