2013-02-23 6 views
10

Вот код -Неправильное преобразование из неподписанные символ * на символ *

1 int main(int argc, char *argv[]) 
    2 { 
    3  signed char S, *psc; 
    4  unsigned char U, *pusc; 
    5  char C, *pc; 
    6 
    7  C = S; 
    8  C = U; 
    9 
10  pc = psc; 
11  pc = pusc; 
12 
13  return 0; 
14 } 

$ gcc test.cpp -o a 
test.cpp: In function ‘int main(int, char**)’: 
test.cpp:10:7: error: invalid conversion from ‘signed char*’ to ‘char*’ [-fpermissive] 
test.cpp:11:7: error: invalid conversion from ‘unsigned char*’ to ‘char*’ [-fpermissive] 

Это составлен на GCC версии 4.6.3 на Ubuntu 12.10 на 32-битной машине Intel.

Учитывая, что char тип is unsigned char x86. -

Если присвоения в строках 7 и 8 для типов, отличных от указателей, являются «ОК», почему ошибки выбрасываются для типов указателей в строках 10 и 11?

Кроме того, должен ли C = U успешно работать без требования?

+0

Вы знакомы с термином ["strict aliasing"] (http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html)? – WhozCraig

+0

Чтение этого материала ... – nightlytrails

+1

'-fpermissive' может вам помочь и игнорировать эту досаду. Просто время от времени вам может понадобиться временно удалить тег снова и посмотреть, не обнаружит ли ваш компилятор другие ошибки, чем этот в вашем проекте, о котором вы должны * беспокоиться. – rsethc

ответ

1

У C++ нет автоматического преобразования указателя, неважно, какие типы указателей на каждой стороне присваивания, если они разные, вам нужен актерский состав.

1

char - это отличный тип от unsigned char и signed char. Гарантируется, что одно из них имеет эквивалентное представление значений, но оно по-прежнему является отдельным типом. Поэтому вы не можете конвертировать из unsigned char* или signed char* в char* (т. Е. Если вы не используете reinterpret_cast). C++ просто не допускает преобразования указателей между различными типами, например, потому что тогда один тип может маскироваться как другой.

Однако преобразование либо unsigned char, либо signed char в char прекрасно подходит, потому что оно просто включает в себя преобразование его значения.

Рассмотрим это следующим образом: вы можете конвертировать int в float, но вы не можете преобразовать int* к float*.

6

Прежде всего, важно подчеркнуть тот факт, что char, signed char и unsigned char все различных типов. Раздел 4.10 Стандарта C++ 11 определяет три возможных стандартных преобразования указателей между указателями разных типов:

1. Константа нулевого указателя представляет собой целочисленное константное выражение (5.19) prvalue целочисленного типа, которое вычисляет нуль или значение prtyue типа std :: nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является нулевое значение указателя этого типа и отличается от любого другого значения указателя объекта или типа указателя функции. Такое преобразование называется преобразованием нулевого указателя. Два значения нулевого указателя того же типа сравниваются равными. Преобразование константы с нулевым указателем в указатель на тип с квалификацией cv - это одно преобразование, а не последовательность преобразования указателя с последующим квалификационным преобразованием (4.4). Константу нулевого указателя интегрального типа можно преобразовать в prvalue типа std :: nullptr_t. [Примечание: полученное значение prvalue не является нулевым значением указателя. -end note]

Это не имеет никакого отношения к виду, поскольку у нас нет нулевых указателей типа nulltptr_t.

2. Prvalue типа «указатель на cv T», где T - тип объекта, может быть преобразован в prvalue типа «указатель на cv void».Результат преобразования «указателя на cv T» в «указатель на cv void» указывает на начало места хранения, где находится объект типа T, как если бы объект был наиболее производным объектом (1.8) типа T (то есть не подобъектом базового класса). Значение нулевого указателя преобразуется в значение нулевого указателя для типа назначения .

Это не может применяться, так как тип назначения не является void. Наконец,

3. Prvalue типа «указатель на cv D», где D - тип класса, может быть преобразован в prvalue типа «указатель на cv B», где B является базовым классом (п.10) D. Если B является недоступным (п. 11) или двусмысленным (10.2) базовым классом D, программа, которая требует этого преобразования, плохо сформирована. Результатом преобразования является указатель на подобъект базового класса объекта производного класса. Значение нулевого указателя преобразуется в значение нулевого указателя типа назначения.

signed char не является базовым классом char, поэтому даже не это относится.

Следовательно, неявное, стандартное преобразование указателя от signed char до char не может быть выполнено.

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

+1

Я думаю, важно подчеркнуть, что 'char',' unsigned char' и 'signed char' - 3 разных типа. Я подозреваю, что вопрос исходит из заблуждения, что 'char' является либо' signed char', либо 'unsigned char'. –

+0

@MaciejHehl: Правда. Я отредактировал ответ, спасибо. –

0

Я мог ошибаться, но, как сказано выше, когда вы назначили «C = S; C = U;», C++ автоматически преобразует его, как если бы вы делали «char x =« h »; printf ("% i ", x);". Однако указатели указывают на определенное место в памяти, и это местоположение имеет размер. Таким образом, при преобразовании вида просто смотрятся на значения под разными углами, указывая на разные значения, может потребоваться изменение размера значения, на которое указывают.