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

Почему я не могу static_cast между char * и unsigned char *?

По-видимому, компилятор считает их несвязанными типами и, следовательно, требуется reinterpret_cast. Почему это правило?

4b9b3361

Ответ 1

Они совершенно разные типы, см. стандарт:

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

1 Объекты, объявленные как символы char), должны быть достаточно большими, чтобы хранить любой член базового набора символов реализации. Если символ из этого набора сохраняется в символьном объекте, интеграл значение этого символьного объекта равно значению единственного символьная буква этого символа. это определение реализации, может ли объект char содержать отрицательный значения. Символы могут быть явно объявлены без знака или
подписан. Обычная char, подписанная char и unsigned charтри различных типа. A char, подписанный char и неподписанный charзанимают одинаковый объем хранения и имеют одинаковое выравнивание требования (basic.types); то есть они имеют один и тот же объект представление. Для типов символов все биты объекта
представление участвует в представлении стоимости. Для неподписанных типы символов, все возможные битовые шаблоны представления значений представляют числа. Эти требования не подходят для других типов. В любая конкретная реализация, простой объект char может те же значения, что и подписанный char или без знака char; который из от реализации.

Таким образом, аналогично этому также возникает следующее:

unsigned int* a = new unsigned int(10);
int* b = static_cast<int*>(a); // error different types

a и b - совершенно разные типы, на самом деле то, что вы ставите под сомнение, является причиной того, что static_cast настолько ограничительный, что он может выполнять следующие задачи без проблем.

unsigned int a = new unsigned int(10);
int b = static_cast<int>(a); // OK but may result in loss of precision

и почему он не может вывести, что целевые типы имеют одинаковую ширину битового поля и могут быть представлены? Он может делать это для скалярных типов, но для указателей, если только цель не получена из источника, и вы хотите выполнить downcast, тогда литье между указателями не будет работать.

Bjarne Stroustrop утверждает, что static_cast полезны в этой ссылке: http://www.stroustrup.com/bs_faq2.html#static-cast, но в сокращенной форме это для пользователя, чтобы четко заявить каковы их намерения и дать компилятору возможность проверить, что то, что вы намереваетесь, может быть достигнуто, поскольку static_cast не поддерживает кастинг между разными типами указателей, тогда компилятор может поймать эту ошибку, чтобы предупредить пользователя, и если они действительно хотят для этого преобразования они должны использовать reinterpret_cast.

Ответ 2

вы пытаетесь преобразовать несвязанные указатели со статическим_кастом. Это не то, для чего используется static_cast. Здесь вы можете увидеть: Type Casting.

С помощью static_cast вы можете преобразовать числовые данные (например, char в unsigned char) или указатель на связанные классы (связанные некоторым наследованием). Это не так. Вы хотите преобразовать один несвязанный указатель в другой, поэтому вам нужно использовать reinterpret_cast.

В основном то, что вы пытаетесь сделать, это компилятор так же, как пытаться преобразовать char * в void *.


Хорошо, вот некоторые дополнительные мысли, почему это допускает принципиально неправильное. static_cast может использоваться для преобразования числовых типов друг в друга. Поэтому вполне законно писать следующее:

char x = 5;
unsigned char y = static_cast<unsigned char>(x);

что также возможно:

double d = 1.2;
int i = static_cast<int>(d);

Если вы посмотрите на этот код в ассемблере, вы увидите, что второй приведение - это не просто повторная интерпретация битового паттерна d, а вместо этого вставляются некоторые инструкции для ассемблера для конверсий.

Теперь, если мы распространим это поведение на массивы, случай, когда достаточно простого способа интерпретации битового шаблона, может работать. Но как насчет литья массивов двойников в массивы ints? То, что вы либо должны заявить, что вам просто нужно переинтерпретировать битовые шаблоны, - там есть механизм для вызванного reinterpret_cast, или вы должны выполнить некоторую дополнительную работу. Как вы видите, простое расширение static_cast для указателя/массивов недостаточно, так как оно должно вести себя подобно static_casting одиночным значениям типов. Это иногда требует дополнительного кода, и неясно определяется, как это должно быть сделано для массивов. В вашем случае - остановка при \0 - потому что это конвенция? Этого недостаточно для нестрочных случаев (число). Что произойдет, если размер типа данных изменится (например, int vs. double на x86-32bit)?

Поведение, которое вы хотите, не может быть правильно определено для всех случаев использования, почему оно не соответствует стандарту С++. В противном случае вам придется помнить такие вещи, как: "Я могу использовать этот тип для другого, если они имеют тип integer, имеют одинаковую ширину и...". Таким образом, это полностью ясно - либо они связаны с CLASSES - тогда вы можете использовать указатели, или они являются числовыми типами, - тогда вы можете использовать значения.

Ответ 3

Помимо указателей, unsigned char * и char * не имеют ничего общего (EdChum уже упомянул о том, что char, signed char и unsigned char - три разных типа). Вы можете сказать то же самое для типов указателей Foo * и Bar * для любых разнородных структур.

static_cast означает, что указатель типа источника может использоваться как указатель типа назначения, для которого требуется отношение подтипа. Следовательно, он не может использоваться в контексте вашего вопроса; вам нужен либо reinterpret_cast, который делает именно то, что вам нужно, либо приведение в стиле C.