2009-10-26 3 views
4

Следующий код компилируется без предупреждения GCC, но выдает предупреждение в Visual Studio 2005.указатель на сопзЬ преобразования в C

const void * x = 0; 
char * const * p = x; 

х указывает на константный объект неизвестного типа, и р указывает на постоянный указатель на char. Почему при присвоении p возникает предупреждение?

Опять же, это C, а не C++. Благодарю.

+0

Не могли бы вы добавить предупреждающее сообщение? – Etan

+2

Согласитесь с Etan: этот вопрос был бы намного яснее, если бы было указано предупреждение. Это: Предупреждение C4090: 'initializing': различные 'const' квалификаторы – user200783

+0

Мой VS2005 (настроенный на C++) на самом деле возвращает ошибку в этом случае: 'initializing': не может преобразовать из 'const void *' в 'char * const * '. Преобразование из 'void *' в указатель на не-'void 'требует явного литья –

ответ

5

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

Итак, для того, чтобы сказать компилятору, что вы на самом деле намерение это сделать, вы должны делать явное приведение, как это:

 const void * x = 0; 
     char * const * p = (char * const *)x; 

P.S. На первом месте я написал «большую часть времени сделано непреднамеренно», но AndreyT заставил меня пересмотреть его, когда он по праву сказал, что void * существует специально для этой цели.

+0

Это подход типа «clobber type» типа C++. правильное решение отличается в C. –

+1

'void *' существует специально для этой цели. Выдача предупреждений об этом будет абсолютно бесполезной. Единственным оправданием для предупреждения в этом случае может быть кажущийся разный уровень косвенности в указателях, а не только потому, что они указывают на разные типы. – AnT

0

Что делать, если x будет указывать, скажем, struct Thing, в отличие от char? В этом случае вы будете делать что-то с неуказанным поведением. GCC имеет тенденцию позволять вам делать это, потому что предполагает, что вы достаточно умны, чтобы не стрелять себе в ногу, но есть веские причины для предупреждения.

+1

gcc давайте сделаем это, потому что стандарт говорит, что 'void *' может быть преобразован в любой тип указателя (в сторону указателей функций) неявно – Christoph

-1
warning C4090: 'initializing' : different 'const' qualifiers 

Вы не можете бросить const void к char *const или даже char *. При разыменовании p теперь вы можете изменить *(char *)(*x). Это малоизвестная тонкость про указатели в С.

Рабочего типа для p будет:

char const **p = x; 

И да, я поставил const на праве, как человек.

+0

предупреждение ошибочно, поскольку сохраняется 'const'ness (не забудьте прочитать декларации наизнанку и что 'const void' совпадает с' void const') – Christoph

+0

nope. запускал это на компиляторе C. проблема заключается в заполнении const void в char * const. с помощью deeffing p теперь вы можете изменить x. –

+1

Это не имеет никакого смысла. Невозможно изменить 'x' через' p'. Мы никогда не принимаем адрес 'x' в любом месте кода. – AnT

0

Вы должны прочитать следующее справа налево.
char * const * p = x;

Пример:
P указывает на указатель const типа char.

3

Код C действителен, и соответствующий компилятор не должен предупреждать, поскольку const ness сохранен правильно, а преобразование void * в любой тип указателя (в сторону указателей функций) неявно.

Компилятор C++ должен предупредить о неявном преобразовании, но предупреждение об отбрасывании квалификатора const является неправильным и должно считаться ошибкой компилятора.

0
const void * x = 0; 
char * const * p = x; 

Сначала я предположил, что вы решили взять адрес x и написали код для этого. Затем я решил, что x указывает на указатель на char [].И в любом случае, и это все еще довольно запутанным:

#include <stdio.h> 
int main() 
{ 
     char s [] = "Hello World!"; 
     const void * x = s; 
     const char * const * const p = (const char * const *)&x; 
     printf("%s\n", *p); 
/* won't compile 
     *p++;  // increments x to point to 'e' 
     (**p)++; // increments 'H' to 'I' 
*/ 
     const char * y = s; 
     x = &y; 
     const char * const * const q = x; 
     printf("%s\n", *q); 
/* won't compile 
     *q++; 
     (**q)++; 
*/ 
     return 0; 
} 

Дополнительный const перед char в декларации p предотвращает (**p)++ от компиляции. Однако добавлено const до объявления q (в GCC) теней warning: dereferencing ‘void *’ pointer с error: increment of read-only location ‘**q’ за (**q)++. Надеюсь, что это поможет, это немного помогло мне :-)

Смежные вопросы