По-видимому, компилятор считает их несвязанными типами и, следовательно, требуется reinterpret_cast
. Почему это правило?
Почему я не могу static_cast между char * и unsigned char *?
Ответы (3)
Они совершенно разных типов см. стандарт:
3.9.1 Основные типы [basic.fundamental]
1 Объекты, объявленные как символы char), должны быть достаточно большими для хранения любого члена базового набора символов реализации. Если символ из этого набора хранится в символьном объекте, интегральное значение этого символьного объекта равно значению односимвольной литеральной формы этого символа. Реализация определяет, может ли объект char содержать отрицательные значения. Символы могут быть явно объявлены беззнаковыми или
подписанными. Обычный символ, подписанный символ и неподписанный символ — это три разных типа. Символ, знаковый символ и неподписанный символ занимают одинаковый объем памяти и имеют одинаковое выравнивание. требования (basic.types); то есть они имеют одно и то же объектное представление. Для символьных типов все биты представления object
участвуют в представлении значения. Для типов символов без знака все возможные битовые комбинации представления значения представляют числа. Эти требования не распространяются на другие типы. В любой конкретной реализации простой объект 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
и почему он не может сделать вывод, что целевые типы имеют одинаковую ширину битового поля и могут быть представлены? Он может сделать это для скалярных типов, но для указателей, если цель не получена из источника, и вы хотите выполнить понижающее приведение, тогда приведение между указателями не будет работать.
Бьерн Страутроп объясняет, почему static_cast
полезны в этой ссылке: http://www.stroustrup.com/bs_faq2.html#static-cast, но в сокращенной форме пользователь должен четко указать свои намерения и дать компилятору возможность проверить, может ли быть достигнуто то, что вы намереваетесь, поскольку static_cast
не поддерживает приведение между различными типами указателей, тогда компилятор может поймать эту ошибку, чтобы предупредить пользователя, и если они действительно хотят выполнить это преобразование, им следует использовать reinterpret_cast
.
unsigned char a = 255; char b = static_cast<char>(a);
?
- person Nick; 14.04.2012
static_cast
между unsigned char*
и char*
, но в основном это потому, что это разные типы, мы не удивлены тем, что вы можете статически приводить между связанными типами, такими как floats
в ints
, а на самом деле беззнаковый char в char, но static_cast
делает то, что делает. Явное преимущество перед приведениями в стиле c заключается в том, что вы получаете ошибки времени компиляции, если пытаетесь преобразовать между разными типами, как в вашем случае, есть соответствующий пост SO: stackoverflow.com/questions/2473628/
- person EdChum; 14.04.2012
int
и double
имеют разную ширину (и даже не представлены одинаково!), поэтому, если вы приведете к double *
, вы можете случайно затоптать часть памяти, если сделаете *d = 3.14
. Мое использование глупости относится только к примитивам одинаковой ширины.
- person Nick; 14.04.2012
static_cast
невозможно между unsigned int*
и int*
, что аналогично твоему вопросу, хранилище и ширина одинаковы для обоих, но static_cast
обнаруживает во время компиляции, что они оба разных типов
- person EdChum; 14.04.2012
int
и float
. Они могут иметь одинаковый размер, но если у вас есть int
, то попробуйте прочитать его как float
, тогда то, что вы получите, зависит от того, как именно float
хранится в памяти. А так как спецификация не говорит, как float
хранится в памяти, спецификация не может определить, как выглядит int
. Помните: стандарт C++ существует, чтобы гарантировать то, что вы получаете. Чтобы определить это поведение, стандарт должен подробно описать, как float
размещается в памяти, а также как int
размещается в памяти.
- person Nicol Bolas; 15.04.2012
static_cast
, однако, является сукой, допускающей безусловное повышение в дереве вывода.
- person Euri Pinhollow; 09.07.2018
вы пытаетесь преобразовать несвязанные указатели с помощью static_cast. static_cast не для этого. Здесь вы можете увидеть: Приведение типов.
С помощью 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, а вместо этого здесь вставлены некоторые ассемблерные инструкции для преобразований.
Теперь, если мы распространим это поведение на массивы, случай, когда достаточно просто другого способа интерпретации битового шаблона, это может сработать. Но как насчет приведения массивов двойных значений к массивам целых чисел? Здесь вы либо должны заявить, что вам просто нужна переинтерпретация битовых шаблонов - для этого есть механизм, называемый reinterpret_cast, либо вы должны выполнить дополнительную работу. Как видите, простого расширения static_cast для указателей/массивов недостаточно, поскольку он должен вести себя аналогично static_casting одиночных значений типов. Иногда для этого требуется дополнительный код, и неясно, как это должно быть сделано для массивов. В вашем случае - остановка на \0 - потому что это соглашение? Этого недостаточно для нестроковых случаев (число). Что произойдет, если размер типа данных изменится (например, int или double на x86-32bit)?
Поведение, которое вы хотите, не может быть правильно определено для всех вариантов использования, поэтому оно не входит в стандарт C++. В противном случае вам пришлось бы помнить такие вещи, как: «Я могу привести этот тип к другому, если они имеют целочисленный тип, имеют одинаковую ширину и ...». Таким образом, совершенно ясно - либо они связаны КЛАССЫ - тогда вы можете приводить указатели, либо они являются числовыми типами - тогда вы можете приводить значения.
T1
связано с T2
, то T1 *
должно быть связано с T2 *
. Почему это правило набора текста не работает (для примитивных типов)?
- person Nick; 14.04.2012
unsigned char a = 255; char b = static_cast<char>(a);
Это кажется немного странным, так как если T1
и T2
являются классами, приведение между указателями не звучит, так как вы могли бы сделать что-то вроде: class A;
class B : public A;
B *b = new B[4];
b[0] = B();
A *a = static_cast<A *>(b);
a[1] = A();
B b1 = b[1]; // oops
Кажется, единственный раз приведение должно быть безопасным между примитивными типами.
- person Nick; 14.04.2012
Помимо указателей, unsigned char *
и char *
не имеют ничего общего (EdChum уже упоминал тот факт, что char
, signed char
и unsigned char
— это три разных типа). Вы можете сказать то же самое для типов указателей Foo *
и Bar *
на любые непохожие структуры.
static_cast
означает, что указатель исходного типа может использоваться как указатель целевого типа, что требует отношения подтипа. Следовательно, его нельзя использовать в контексте вашего вопроса; вам нужен либо reinterpret_cast
, который делает именно то, что вы хотите, либо приведение в стиле C.
c_str()
возвращаетconst char *
, а функция SHA-1 принимаетconst unsigned char *
в качестве аргумента. - person Nick   schedule 14.04.2012c
станетc + 256
, как это принято при преобразовании байта со знаком в байт без знака. Честно говоря, я просто делаю преобразование, чтобы вычислить хеш-значение. Меня не волнует, как они конвертируются, пока они конвертируются одинаково каждый раз. - person Nick   schedule 14.04.2012char
вunsigned char
— это преобразование. Преобразованиеchar *
вunsigned char*
и последующее чтение элементов, предполагая, что они были преобразованы, когда это не так, сильно отличается. Он будет работать в системе, где преобразование на самом деле не требует изменения представления (например, в системе дополнения до двух), но, поскольку это предположение, зависящее от реализации, уместно, что требуется явноеreinterpret_cast
. - person CB Bailey   schedule 14.04.2012