Предупреждение PIC 364, связанное с инициализацией const

В Интернете я не нашел ответов на этот вопрос, а за последние 4 месяца я просмотрел его дважды.

В MPLab v8.88 с использованием компилятора Hi-Tech ANSI C у меня есть эта строка кода:

const   uint8 SUM_THRESHOLD_MIN = 15;   /* comment edited out   */

и я получаю предупреждение:

Warning [364] C:\*directory edited out* \ *filename_edited_out*.c; 273.35 attempt to modify object qualifed const

(извините за правки, но я чувствовал, что должен отредактировать личные, но лишние детали).

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

constВ одном и том же блоке кода происходит несколько инициализаций, и все они выдают мне это предупреждение. Они находятся в файле .c, в функции void. У меня есть другие файлы с функциями void, в которых я инициализирую const uint8, и в этих файлах нет предупреждений. Я искал глобально и не нашел другого экземпляра переменной, кроме того, где она используется в функции void (так что нет никаких проблем с переопределением или чем-то подобным). Чтобы было ясно, эти константы не являются частью какой-либо структуры или чего-то странного, они просто объявлены в функции void в файле .c.

У меня uint8 правильно typedef'd, а не #define'd (см. комментарии).

Может ли кто-нибудь помочь мне избавиться от этого предупреждения?

РЕДАКТИРОВАТЬ: Если я вставлю один из const uint8 в другой файл .c сразу после const uint16, который не выдает ошибку, например:

const uint16 rate_bias_time_constant[NUM_RATE_CHANNELS][RATE_BIAS_STEP_MAX] = 
    {30,120,480,960,  300,120,180,240,  300,120,180,240 }; // comment edited out
const   uint8 SUM_THRESHOLD_MIN = 15;   /* comment edited out   */

Я получаю предупреждение 364 в этом файле для этого const uint8, но не для const uint16. Если я изменю SUM_THRESHOLD_MIN с uint8 на uint16, я все равно получу предупреждение. Для полноты, если я изменю его со всех прописных на все строчные, я все равно получу предупреждение. Если я изменю строку, например:

const uint8 SUM_THRESHOLD_MIN[2] = {15,2};  /* comment edited out   */

Предупреждения нет.

Является uint8правильным typedefили просто #define?
Код говорит: «typedef unsigned char uint8;» а в другом файле есть const int16 и uint8, инициализированные одинаково без предупреждений.
Это фрагмент кода в файле заголовка (.h), который может быть включен несколько раз в файл .c?
Строка кода находится внутри функции или вне функции?
Фрагмент кода, который выдает предупреждение, находится в файле .c. Все uint8 (есть 8 предупреждений) и одно объявление int16 const в этом файле выдают это предупреждение, но есть const char и const unsigned int, которые не выдают предупреждение в этом .c-файле, и есть объявления const uint8 в других файлах, которые не выдают предупреждения.
@Joe Hass, это функция void, и const uint8 в других файлах также находятся в функциях void.
Можете ли вы предоставить некоторую информацию о «блоке кода», в котором возникают эти ошибки?
Вы должны предоставить больше информации (весь модуль .c), если хотите получить хорошие ответы.
Случайно, нет ли в других файлах встроенных директив компилятора (например, #pragmas), которые отключают это конкретное предупреждение?
@m.Alin: Боюсь, я не могу опубликовать весь файл (код компании), но я постараюсь ответить на вопросы, которые помогут в этом разобраться.
@Dave Tweed: нет #pragma для отключения предупреждений в других файлах. Я, наверное, первый человек, которого вообще волнует наличие предупреждений, скомпилированных этим кодом. Я подумал об использовании прагмы подавления предупреждений, но другие файлы в этом проекте не доставляют мне проблем...
@ user28910: это в файле .c, после #includes, после локальных прототипов, в третьей функции файла, функции void, а константа, вызывающая проблемы, находится в середине объявления остальных локальные переменные в этой функции void. Константа int16, которая выдает предупреждение, находится в той же функции, локально объявленной после «если». Существует const unsigned int и const char, которые не выдают предупреждения в этом же файле, а другие файлы содержат const uint8 и не выдают предупреждение.
Как вы строите проект — компилируете ли вы файлы из командной строки, используя Makefile, используя IDE? Можете ли вы сделать копию рабочего файла и скомпилировать его без предупреждений?
@Dave Tweed: я использую MPLab IDE v8.88, используя кнопку «перестроить». Я не понимаю, что вы имеете в виду, говоря о создании копии рабочего файла. Обратите внимание, что я редактировал компилятор C: я использую компилятор Hi-Tech ANSI C, а не C18.
Возьмите файл, который компилируется без предупреждений, и сделайте его копию с другим именем. Можете ли вы скомпилировать его без предупреждений? Существуют ли настройки для каждого файла в самой среде IDE, которые могут подавлять предупреждения?
@Dave Tweed: я не понимаю, куда вы собираетесь создавать копию файла, и я уверен, что это мое собственное невежество: если я справлюсь и вставлю в текущий проект и добавлю другой файл, я получать ошибки, потому что у меня будут одни и те же имена функций несколько раз, и если я создам новый проект, я не смогу собрать его, потому что у него не будет main и т. д. Могу ли я скомпилировать отдельные файлы C, в которых отсутствует main()? Если да, то как?
Хорошо, я попытался вставить одну из строк, которые выдавали код предупреждения, в другой файл, и он тоже выдает предупреждение. Затем я попытался просмотреть эту строку глобально (вне функции), и предупреждения не было. Мы приближаемся, но мы еще не там...
Можете ли вы вырезать и вставить всю эту функцию в один из файлов, который компилируется без предупреждений и имеет похожие объявления const, и посмотреть, получите ли вы там эти предупреждения?
Да, добавьте копию файла в проект и игнорируйте другие ошибки. Или переименовать функции в копии, не важно. Суть в том, чтобы найти минимальный набор различий между двумя файлами, от которых зависит получение конкретного предупреждения или нет.
@Bob, не могли бы вы пропустить функцию void там, где она вызывается? Нам не нужно все содержимое функции, но, возможно, несколько первых строк и некоторый код, который вызывает функцию.
Я решил это, см. ниже. Надеюсь, что следующий парень, у которого будет эта ошибка, не останется с 1 результатом поиска Google: русский веб-сайт без полезной информации... Еще раз спасибо за помощь

Ответы (3)

Я понял, и всем большое спасибо за помощь!

Объявления, которые не выдают предупреждения, являются либо массивами, либо объявлены статическими константами uint8/16. По какой-то причине компилятор Hi-Tech C нормально работает с const int/char, const uint8/16, которые являются массивами, но не с const uint8/16, если они не объявлены как static const uint8/16.

Вы должны понимать, что из-за странной архитектуры PIC16/18 квалификатор "const" является указанием поместить эту переменную во флэш-память вместо ОЗУ, а не указанием компилятору запретить ее изменение.

Если вы пытаетесь инициализировать значение автоматической переменной, которая является локальной для функции, то вы пытаетесь изменить ее во время выполнения, потому что она попытается записать это значение инициализации в переменную (которая хранится во Flash и поэтому не (легко) записываемый) каждый раз, когда функция выполняется. Причина, по которой это работает, когда переменная объявлена ​​статической, заключается в том, что статические переменные, которые являются локальными для функций, инициализируются только один раз, поэтому у компилятора нет логической несогласованности, о которой можно было бы ныть. Я предполагаю, что массивы const обрабатываются одинаково.

Это не объясняет, почему когда вы используете char или int в отличие от int16/8 или uint16/8, это не выдает одно и то же предупреждение, но потенциально может объяснить, почему глобальная константа int16/8 не давала Ошибка. Это странная проблема, связанная с компилятором. Вы уверены, что они размещены во флэш-памяти? Я продолжаю задаваться вопросом об этом для PIC, и однажды прошел некоторую разборку, но никогда не был на 100% уверен. Я думал, что у Pics есть место для кода и место в памяти, а инструкции имеют длину 14 бит или что-то в этом роде...
PIC16 имеют 14-битную флэш-память (6-битный код операции, 8-битный операнд); PIC18 имеют 16-битную флэш-память. Оба хранят константные переменные во флэш-памяти; Некоторым компиляторам PIC16 можно приказать упаковывать строки размером 2x7 бит в каждое 14-битное слово, что может затруднить чтение при отладке. Оба семейства имеют полностью отдельные области кода и данных; прочтите главы о памяти в любом листе данных PIC16/18 для хорошего объяснения. Я не могу объяснить проблему "int/char работает, а int8/int16 нет", это вообще не имеет смысла - как бы вы ни описали char, компилятор должен вести себя точно так же.
Мне пришло в голову, что причина, по которой массивы auto const не выдавали ошибок, заключается в том, что const char[] на самом деле является const char *; указатель находится в оперативной памяти, а данные, на которые он ссылается, находятся во флэш-памяти. Указатель можно перезаписывать (чтобы он указывал на один и тот же объект во флэш-памяти) каждый раз, когда функция выполняется, не вызывая никаких проблем. Кроме того, вы можете попробовать решить проблему с char-v-uint8, используя #define вместо typedef.

Я думаю, что основная проблема заключается в ваших ожиданиях того, как CONST работает с этим компилятором на этом процессоре. Эти вещи не являются переменными, как вы, кажется, ожидаете от своего описания. Скорее всего, они реализованы как константы в программной памяти, которая по существу доступна только для чтения. Эти вещи нельзя изменить во время выполнения. Ошибка, которую вы получаете, вероятно, связана с кодом среды выполнения, пытающимся записать в CONST, а не в определение CONST.

Ничто из этого не объясняет, почему в некоторых местах его проекта это работает, а в других нет.
Однако он не пытается изменить значение. Вам разрешено инициализировать константу; это довольно бесполезно, если вы не можете.
@Dave: Возможно, он пытается назначить CONST только во время выполнения в модулях, которые терпят неудачу.
@user: совсем не ясно, что он не пытается изменить значение во время выполнения.
Мы не меняем значение во время выполнения. Предупреждение указывает на строку кода, и эта строка является объявлением константы.