Что означает эта ошибка? Я не могу решить это никак.
предупреждение: не рекомендуется преобразовывать строковую константу в 'char *' [-Wwrite-strings]
programming
arduino-ide
c
Федерико Корацца
источник
источник
Ответы:
Как обычно, я собираюсь предоставить немного справочной технической информации о причинах и причинах этой ошибки.
Я собираюсь изучить четыре различных способа инициализации строк C и посмотреть, в чем заключаются различия между ними. Это четыре вопроса:
Теперь для этого я хочу заменить третью букву «i» на «o», чтобы сделать ее «Thos - это какой-то текст». Во всех случаях (как вы думаете) это может быть достигнуто путем:
Теперь давайте посмотрим, что делает каждый способ объявления строки и как это
text[2] = 'o';
утверждение повлияет на вещи.Во- первых, наиболее часто видели путь:
char *text = "This is some text";
. Что это буквально означает? Ну, в C это буквально означает «Создайте переменную с именем,text
которая будет указателем чтения-записи на этот строковый литерал, который содержится в пространстве только для чтения (кода)». Если у вас включена опция,-Wwrite-strings
вы получите предупреждение, как показано в вопросе выше.По сути это означает «Предупреждение: вы попытались создать переменную, которая будет указывать чтение-запись на область, в которую вы не можете писать». Если вы попытаетесь установить третий символ на «o», вы на самом деле попытаетесь записать в область только для чтения, и все будет не очень хорошо. На традиционном ПК с Linux это приводит к:
Теперь второй
char text[] = "This is some text";
. Буквально в C это означает «Создать массив типа« char »и инициализировать его с данными« Это некоторый текст \ 0 ». Размер массива будет достаточно большим для хранения данных». Таким образом, это фактически выделяет ОЗУ и копирует значение «Это некоторый текст \ 0» во время выполнения. Нет предупреждений, нет ошибок, совершенно верно. И правильный способ сделать это, если вы хотите иметь возможность редактировать данные . Давайте попробуем запустить командуtext[2] = 'o'
:Это сработало, отлично. Хорошо.
Теперь третий путь:
const char *text = "This is some text";
. Опять буквальное значение: «Создать переменную с именем« text », которая будет указателем только для чтения на эти данные в постоянной памяти». Обратите внимание, что и указатель, и данные теперь доступны только для чтения. Нет ошибок, нет предупреждений. Что произойдет, если мы попробуем запустить нашу тестовую команду? Ну, мы не можем. Компилятор теперь интеллектуален и знает, что мы пытаемся сделать что-то плохое:Это даже не скомпилируется. Попытка записи в постоянную память теперь защищена, поскольку мы сказали компилятору, что наш указатель предназначен только для постоянной памяти. Конечно, он не обязательно должен указывать на постоянную память, но если вы укажете на память чтения-записи (RAM), эта память все равно будет защищена от записи компилятором.
Наконец последняя форма:
const char text[] = "This is some text";
. Опять же, как и прежде,[]
он выделяет массив в ОЗУ и копирует в него данные. Однако теперь это массив только для чтения. Вы не можете писать в него, потому что указатель на него помечен какconst
. Попытка записи в него приводит к:Итак, краткое описание того, где мы находимся:
Эта форма является полностью недействительной и ее следует избегать любой ценой. Это открывает двери для всех видов плохих вещей, происходящих:
Эта форма является правильной, если вы хотите сделать данные редактируемыми:
Эта форма является правильной, если вы хотите строки, которые не будут редактироваться:
Эта форма кажется бесполезной ОЗУ, но она имеет свое применение. Лучше забудьте об этом сейчас.
источник
PROGMEM
,PSTR()
илиF()
. Таким образом,const char text[]
не использует больше оперативной памяти, чемconst char *text
.(const char *)(...)
приведение. Нет реального эффекта, если плате это не нужно, но большая экономия, если вы затем перенесете свой код на плату, которая в этом нуждается.Чтобы уточнить отличный ответ Макенко, есть веская причина, почему компилятор предупреждает вас об этом. Давайте сделаем тестовый эскиз:
У нас есть две переменные, foo и bar. Я изменяю один из них в setup (), но вижу результат:
Они оба изменились!
На самом деле, если мы посмотрим на предупреждения, мы видим:
Компилятор знает, что это хитроумно, и это правильно! Причина этого в том, что компилятор (разумно) ожидает, что строковые константы не изменятся (так как они являются константами). Таким образом, если вы ссылаетесь на строковую константу
"This is some text"
несколько раз в своем коде, то разрешается выделять им одну и ту же память. Теперь, если вы измените один, вы измените все из них!источник
*foo
и*bar
использование различных строковых «констант» предотвратить это? Кроме того, как это отличается от отсутствия строк вообще, какchar *foo;
:?new
,strcpy
иdelete
).Либо прекратите пытаться передать строковую константу, где функция принимает значение
char*
, либо измените функцию, чтобы она взялаconst char*
вместо этого.Строка типа «случайная строка» является константой.
источник
Пример:
Предупреждение:
Функция
foo
ожидает символ * (который поэтому может изменить), но вы передаете строковый литерал, который не должен изменяться.Компилятор предупреждает вас не делать этого. Будучи устаревшим, он может превратиться из предупреждения в ошибку в будущей версии компилятора.
Решение: заставьте foo взять const char *:
Более старые версии C (и C ++) позволяют писать код, как в моем примере выше. Вы можете создать функцию (например
foo
), которая печатает что-то, что вы передаете ей, а затем передаете литеральную строку (например,foo ("Hi there!");
).Однако функции, которая принимает
char *
в качестве аргумента, разрешено изменять свой аргумент (т.е. изменятьHi there!
в этом случае).Вы могли бы написать, например:
К сожалению, передавая литерал, вы теперь потенциально изменили этот литерал так, чтобы «Привет!» сейчас "До свидания", что не хорошо. Фактически, если вы скопировали более длинную строку, вы можете перезаписать другие переменные. Или, в некоторых реализациях вы получите нарушение доступа, потому что "Привет!" возможно, был помещен в постоянную (защищенную) оперативную память.
Таким образом, авторы компиляторов постепенно осуждают это использование, поэтому функции, которым вы передаете литерал, должны объявить этот аргумент как
const
.источник
can not
быть изменены?У меня есть эта ошибка компиляции:
Пожалуйста, замените эту строку:
#define TIME_HEADER "T" // Header tag for serial time sync message
с этой строкой:
#define TIME_HEADER 'T' // Header tag for serial time sync message
и сборка идет хорошо.
источник