РЕДАКТИРОВАТЬ: проблема объясняется более подробно здесь (спасибо @Eric Postpischil).Кажется, это ошибка в GCC.
Сначала позвольте мне начать с некоторого контекста: код, который я пишу, использует API, который я не могу изменить, в версии GCC, которую я не могу изменить,с флагами компиляции мне не разрешено удалять, и когда я закончу с этим, у него должно быть ровно ноль предупреждений или # прагм.
РЕДАКТИРОВАТЬ: также нет союзов.Система сборки также использует -Wall -ansi -pedantic и любые другие предупреждения под солнцем.Я подтвердлю версию GCC завтра, но я почти уверен, что она не выше GCC 7. Тем временем я тестирую с GCC 6.3.
EDIT3: я отмечаю проблему как «отвеченную».Для полноты картины я добавляю немного дополнительной информации ниже:
Я проверил используемую версию компилятора, и она не очень хороша.Мы используем Mingw, и gcc.exe --version
сообщает мне, что это GCC 3.4.5.
Кроме того, флаги компиляции включают wall wextra wcast-qual wpointer-arith wconversion wsign-conversion
наряду с другими, которые не имеют отношения к рассматриваемой проблеме.
Проблема
Рассмотрим следующий код:
#include "stdio.h"
#include "stdint.h"
typedef uint32_t MyType[4];
const MyType* foo(const uint8_t* a)
{
return (const MyType*) a;
}
void myapi_foo(const MyType* d) {}
int main()
{
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
myapi_foo(b);
return 0;
}
Скомпилированный с GCC и флагом -Wcast-qual, этот код выдаст следующее предупреждение:
предупреждение: приведение отбрасывает квалификатор 'const' из целевого типа указателя [-Wcast-qual] return (const MyType *) a;
EDIT: чтобы уточнить, ошибка в этой строке:
return (const MyType*) a;
Причина проблемы
Я знаю, что основной причиной проблемы является typedef type MyType
, который на самом деле является массивом.К сожалению, я не могу позволить себе роскошь изменять этот typedef, а также функцию API myapi_foo
и сомнительный выбор типа параметра.Честно говоря, я не совсем понимаю, , почему компилятор так недоволен этим исполнением, поэтому разъяснения более чем приветствуются.
Вопрос
Что будет самый чистый способ указания компилятору, что все должно рассматриваться как указатель на постоянные данные?
Отклоненные и потенциальные решения
Вот несколько «решений», которые янашел, но оставил меня неудовлетворенным:
- Снимите флаг -Wcast-qual .Я не могу этого сделать из-за правил качества кода.
- Добавьте #pragma, чтобы отключить предупреждение вокруг этой части кода (как показано здесь ).Точно так же мне не разрешено это делать.
- Привести указатель к целому числу, затем привести обратно к указателю (как показано здесь )
return (const MyType*) (uint32_t) a;
.Это очень грубо, но использование uint32_t
в качестве адресов памяти имеет прецедент в этом проекте, поэтому мне, возможно, придется использовать его в качестве последней попытки. - EDIT: @bruno предложил использовать объединениеобойти проблему.Это портативное и довольно элегантное решение.Однако вышеупомянутые правила качества кода прямо запрещают использование союзов.
- EDIT: @Eric Postpischil и @MM предложили использовать (const void *) приведение
return (const void*) a;
, которое будет работать независимо от значения sizeof(MyType*)
.К сожалению, это не работает на цель.
Спасибо за ваше время.