Приведение указателя const void к массиву указателей const char правильно в C

у меня есть кусок кода на C, который выглядит так:

const char (*foo)[2] = bar();

теперь bar() - это функция, которая возвращает (const void *). Как мне правильно бросить это const указатель? Код выдает это предупреждение от GCC:

"initialization discards qualifiers from pointer target type".   

вот некоторые из моих неудачных попыток:

const char (*foo)[2] = (const char *)bar();
const char (*foo)[2] = (const void **)bar();

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

EDIT : это было предложил:

const char (*foo)[2] = (const char (*)[2])bar();

это кажется правильным, но GCC дает это предупреждение:

"cast discards qualifiers from pointer target type"   

который почти идентичен первоначальному предупреждению.

EDIT 2: хорошо, думаю, я понял. Реальная проблема здесь -( const void * ) определение bar(). The const в определении (const char( * )[2]) относится к элементам массива, а не указатель на массив. Это определение типа по существу является массивом, который при представлении void указатель не const. Реальный ответ заключается в том, что ( const void * ) теряет const-Несс когда бросание к (const char ( * )[2]).

5 ответов


несколько других заявили правильный бросок, но он генерирует ложные предупреждения. Это предупреждение исходит от возможного ошибка в стандарте C или (в зависимости от вашей интерпретации) случай, который GCC должен рассматривать специально. Я верю const классификатор можно безопасно и однозначно поднять до типа массива. Вы можете отбросить это предупреждение с -Wno-cast-qual но, конечно, это устранит предупреждения для случаев, которые вам действительно важны о.

чтобы уточнить, тип const char (*)[2] означает "указатель на массив (длина 2) из const char". Массив не помечен const, только элементы массива. По сравнению с типом const void *, компилятор замечает, что последний является указателем на const, где как первое нет, таким образом, генерируя предупреждение. Стандарт C не предоставляет возможности пометить массив как const, хотя a const массив будет эквивалентен массиву const.


попробуй:

const char (*foo)[2] = (const char (*)[2])bar();

редактировать но если bar возвращает указатель на массив const указателей символов в качестве подсказок заголовка вопроса, не должно быть необходимости в приведении, если вы назначаете переменной этого типа:

char* const* foo = bar();

проблема с предупреждением в последней версии cast имеет исторические корни. Вы знаете, что язык C (а также C++) правильно запрещает T** -> const T** преобразования. Это правильно, так как разрешение этого преобразования откроет путь для некоторых тонких нарушений правил const-correctness (можно найти в любом уважающем себя FAQ).

однако язык C также запрещает T** -> const T* const* преобразования. Это отличается от C++, который позволяет это преобразование. (Это преобразование не нарушает const-корректность.) Это уже давно считается "дефектом дизайна" в спецификации языка C. Этот дефект был "исправлен" в C++, но он продолжает сохраняться в C (даже в C99). Честно говоря, я понятия не имею, почему он остался неизменным в C99. Одним из" выпадений " этого дефекта (или, точнее, этого подхода к лечению const-корректности) является то, что на языке C T (*)[N] -> const T (*)[N] преобразование также остается запрещенным, даже если оно не несет в себе угрозы с const-корректность.

Я не могу воспроизвести предупреждение, которое вы получаете с моей версией GCC. Но если вы получаете это, это кажется просто еще одним следствием той же идеологии. Если принять во внимание, что преобразование было запрошено явным оператором приведения, предупреждение GCC совершенно неоправданно. Вы можете попытаться обойти предупреждение, используя цепной бросок

const char (*foo)[2] = (const char (*)[2]) (void *) bar();

просто Примечание, вам не нужны размеры массива:

const void *bar() { 
    static const char a[10] = "abcdefghij";
    return &a[4];
}

int main() {
    const char (*foo)[2] = (const char (*)[])bar();
    return 0;
}

Так это может быть трудно для некоторых образом:

cdecl> explain const char (*foo)[2]
declare foo as pointer to array 2 of const char

const char (*foo)[2] = (const char (*)[2])bar();