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

Безопасно ли отличать unsigned char * to char * и обрабатывать разыменованный указатель, как если бы он действительно указывал на char?

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


ВОПРОС

Это выглядит хорошо, но гарантирует ли стандарт, что значение (1) всегда будет истинным?

char unsigned * p1 = ...;
char          * p2 = reinterpret_cast<char *> (p1);

*p1 == *p2; // (1)
4b9b3361

Ответ 1

ЭТО МОЖЕТ УДОВЛЕТВОРИТЬ,

но нет такой гарантии в стандарте С++ 11 (N3337), ни в предстоящем С++ 14 (N3797).

char unsigned * p1 = ...;
char          * p2 = reinterpret_cast<char *> (p1);

*p1 == *p2; // (1), not guaranteed to be true

Примечание. Это конкретная реализация, независимо от того, подписан ли char или без знака; [basic.fundamental]p1.



ПОДРОБНОСТИ

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

  • имеют одинаковое требование выравнивания;
  • занимают одинаковое количество хранилища и
  • что все биты хранилища, занятые символьным типом, должны участвовать в представлении значений и;
  • что представление значения одинаков.

Обмен тем же объемом хранения, требованиями к выравниванию и гарантией участия в бит означает, что листинг lvalue, относящийся к одному типу (без знака char), другому (char), является безопасным.. насколько это возможно как фактическое литье.

3.9.1p1 Основные типы [basic.fundamental]

Определяется реализацией, может ли char сохранять отрицательные значения. Символы могут быть явно объявлены signed или unsigned.

     

A char, a signed char, и a unsigned char занимают одинаковое количество хранения и имеют одинаковые требования к выравниванию (3.11); то есть они имеют одно и то же представление объекта. Для типов символов в представлении значений участвуют все биты представления объекта.

     

Для неподписанных типов символов все возможные битовые шаблоны представления значений представляют числа. Эти требования не подходят для других типов.

3.9p4 Типы [basic.types]

Объектное представление объекта типа T представляет собой последовательность объектов N unsigned char, занятых объектом типа T,, где N равно sizeof(T). Представление значения объекта - это набор битов, которые содержат значение типа T.



SO, ЧТО ПРОБЛЕМА?

Если мы назначим максимальное значение unsigned char (UCHAR_MAX) на *p1 и *p2, *p2 не будет способный представлять это значение. Мы переполним *p2 и, скорее всего, получим значение -1.

Примечание: целочисленное переполнение цепочки - это фактически поведение undefined.


*p1 = UCHAR_MAX;

*p1 == *p2; // (1)

Обе стороны operator== должны иметь один и тот же тип, прежде чем мы сможем их сравнить, и в настоящее время одна сторона unsigned char, а другая char.

Компилятор должен использовать интегральную рекламу, чтобы найти тип, который может представлять все комбинированные возможные значения двух типов; и в этом случае результирующий тип будет int.

После цельной акции утверждение семантически эквивалентно int (UCHAR_MAX) == int(-1), что, конечно, ложно.

Ответ 2

strcmp (buf1, reinterpret_cast<char const *> (buf2));

Это выглядит отлично,

Это. strcmp принимает параметры const char *, но внутренне преобразует их в const unsigned char * (если требуется), так что даже если char подписан и два разных байта могут сравниться равными при просмотре их как char, они по-прежнему будут сравнивать при просмотре их с помощью strcmp.

C99:

7.21 Обработка строк <string.h>

7.21.1 Стандартные условные обозначения

3 Для всех функций в этом подпункте каждый символ должен интерпретироваться так, как если бы он имел тип unsigned char (и, следовательно, все возможные представления объекта действительны и имеют другое значение).

Тем не менее,

но гарантирует ли стандарт, что значение (1) всегда будет истинным?

char unsigned * p1 = ...;
char          * p2 = reinterpret_cast<char *> (p1);

*p1 == *p2; // (1)

То, что вы написали, не гарантируется.

Возьмем общую реализацию с подписанными char, 8-битными байтами с использованием двух дополнительных представлений. Если *p1 - UCHAR_MAX, то *p2 == -1 и *p1 == *p2 будет false, потому что продвижение до int дает им разные значения.

Если вы имели в виду либо (char) *p1 == *p2, либо *p1 == (unsigned char) *p2, то они все еще не гарантированы, поэтому вам нужно убедиться, что если вы скопируете из массива char в массив unsigned char, вы не включайте такое преобразование.