Что означает эта ошибка? Я не могу решить это никак.
предупреждение: не рекомендуется преобразовывать строковую константу в 'char *' [-Wwrite-strings]
Что означает эта ошибка? Я не могу решить это никак.
предупреждение: не рекомендуется преобразовывать строковую константу в 'char *' [-Wwrite-strings]
Ответы:
Как обычно, я собираюсь предоставить немного справочной технической информации о причинах и причинах этой ошибки.
Я собираюсь изучить четыре различных способа инициализации строк C и посмотреть, в чем заключаются различия между ними. Это четыре вопроса:
char *text = "This is some text";
char text[] = "This is some text";
const char *text = "This is some text";
const char text[] = "This is some text";
Теперь для этого я хочу заменить третью букву «i» на «o», чтобы сделать ее «Thos - это какой-то текст». Во всех случаях (как вы думаете) это может быть достигнуто путем:
text[2] = 'o';
Теперь давайте посмотрим, что делает каждый способ объявления строки и как это 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 », которая будет указателем только для чтения на эти данные в постоянной памяти». Обратите внимание, что и указатель, и данные теперь доступны только для чтения. Нет ошибок, нет предупреждений. Что произойдет, если мы попробуем запустить нашу тестовую команду? Ну, мы не можем. Компилятор теперь интеллектуален и знает, что мы пытаемся сделать что-то плохое:
ошибка: назначение места только для чтения '* (текст + 2u)'
Это даже не скомпилируется. Попытка записи в постоянную память теперь защищена, поскольку мы сказали компилятору, что наш указатель предназначен только для постоянной памяти. Конечно, он не обязательно должен указывать на постоянную память, но если вы укажете на память чтения-записи (RAM), эта память все равно будет защищена от записи компилятором.
Наконец последняя форма: const char text[] = "This is some text";
. Опять же, как и прежде, []
он выделяет массив в ОЗУ и копирует в него данные. Однако теперь это массив только для чтения. Вы не можете писать в него, потому что указатель на него помечен как const
. Попытка записи в него приводит к:
ошибка: назначение места только для чтения '* (текст + 2u)'
Итак, краткое описание того, где мы находимся:
Эта форма является полностью недействительной и ее следует избегать любой ценой. Это открывает двери для всех видов плохих вещей, происходящих:
char *text = "This is some text";
Эта форма является правильной, если вы хотите сделать данные редактируемыми:
char text[] = "This is some text";
Эта форма является правильной, если вы хотите строки, которые не будут редактироваться:
const char *text = "This is some text";
Эта форма кажется бесполезной ОЗУ, но она имеет свое применение. Лучше забудьте об этом сейчас.
const char text[] = "This is some text";
PROGMEM
, PSTR()
или F()
. Таким образом, const char text[]
не использует больше оперативной памяти, чем const char *text
.
(const char *)(...)
приведение. Нет реального эффекта, если плате это не нужно, но большая экономия, если вы затем перенесете свой код на плату, которая в этом нуждается.
Чтобы уточнить отличный ответ Макенко, есть веская причина, почему компилятор предупреждает вас об этом. Давайте сделаем тестовый эскиз:
char *foo = "This is some text";
char *bar = "This is some text";
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo [2] = 'o'; // change foo only
Serial.println (foo);
Serial.println (bar);
} // end of setup
void loop ()
{
} // end of loop
У нас есть две переменные, foo и bar. Я изменяю один из них в setup (), но вижу результат:
Thos is some text
Thos is some text
Они оба изменились!
На самом деле, если мы посмотрим на предупреждения, мы видим:
sketch_jul14b.ino:1: warning: deprecated conversion from string constant to ‘char*’
sketch_jul14b.ino:2: warning: deprecated conversion from string constant to ‘char*’
Компилятор знает, что это хитроумно, и это правильно! Причина этого в том, что компилятор (разумно) ожидает, что строковые константы не изменятся (так как они являются константами). Таким образом, если вы ссылаетесь на строковую константу "This is some text"
несколько раз в своем коде, то разрешается выделять им одну и ту же память. Теперь, если вы измените один, вы измените все из них!
*foo
и *bar
использование различных строковых «констант» предотвратить это? Кроме того, как это отличается от отсутствия строк вообще, как char *foo;
:?
new
, strcpy
и delete
).
Либо прекратите пытаться передать строковую константу, где функция принимает значение char*
, либо измените функцию, чтобы она взяла const char*
вместо этого.
Строка типа «случайная строка» является константой.
Пример:
void foo (char * s)
{
Serial.println (s);
}
void setup ()
{
Serial.begin (115200);
Serial.println ();
foo ("bar");
} // end of setup
void loop ()
{
} // end of loop
Предупреждение:
sketch_jul14b.ino: In function ‘void setup()’:
sketch_jul14b.ino:10: warning: deprecated conversion from string constant to ‘char*’
Функция foo
ожидает символ * (который поэтому может изменить), но вы передаете строковый литерал, который не должен изменяться.
Компилятор предупреждает вас не делать этого. Будучи устаревшим, он может превратиться из предупреждения в ошибку в будущей версии компилятора.
Решение: заставьте foo взять const char *:
void foo (const char * s)
{
Serial.println (s);
}
Я не понимаю Вы имеете в виду не может быть изменено?
Более старые версии C (и C ++) позволяют писать код, как в моем примере выше. Вы можете создать функцию (например foo
), которая печатает что-то, что вы передаете ей, а затем передаете литеральную строку (например, foo ("Hi there!");
).
Однако функции, которая принимает char *
в качестве аргумента, разрешено изменять свой аргумент (т.е. изменять Hi there!
в этом случае).
Вы могли бы написать, например:
void foo (char * s)
{
Serial.println (s);
strcpy (s, "Goodbye");
}
К сожалению, передавая литерал, вы теперь потенциально изменили этот литерал так, чтобы «Привет!» сейчас "До свидания", что не хорошо. Фактически, если вы скопировали более длинную строку, вы можете перезаписать другие переменные. Или, в некоторых реализациях вы получите нарушение доступа, потому что "Привет!" возможно, был помещен в постоянную (защищенную) оперативную память.
Таким образом, авторы компиляторов постепенно осуждают это использование, поэтому функции, которым вы передаете литерал, должны объявить этот аргумент как const
.
can not
быть изменены?
У меня есть эта ошибка компиляции:
TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
if(Serial.find(TIME_HEADER)) {
^
Пожалуйста, замените эту строку:
#define TIME_HEADER "T" // Header tag for serial time sync message
с этой строкой:
#define TIME_HEADER 'T' // Header tag for serial time sync message
и сборка идет хорошо.