устаревшее преобразование из строковой константы в 'char *'

Что означает эта ошибка? Я никак не могу его решить.

  

предупреждение: устаревшее преобразование из строковой константы в 'char *' [-Wwrite-stringings]

10 голосов | спросил Federico Corazza 14 J000000Tuesday15 2015, 05:20:15

5 ответов


20

Как я привык, я собираюсь предоставить небольшую справочную техническую информацию в whys и wherefores этой ошибки.

Я собираюсь проверить четыре разных способа инициализации строк 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':

  

Thos - это текст

Это сработало, отлично. Хорошо.

Теперь третий способ: const char *text = "This is some 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";
ответил Majenko 14 J000000Tuesday15 2015, 18:10:36
4

Либо прекратите пытаться передать строковую константу, где функция принимает символ char*, либо измените функцию так, чтобы вместо этого она использовала const char*.

Строка типа «случайная строка» - это константы.

ответил Ignacio Vazquez-Abrams 14 J000000Tuesday15 2015, 05:22:22
4

Чтобы подробно остановиться на превосходном ответе Макенко, есть веская причина, по которой компилятор предупреждает вас об этом. Давайте сделаем тестовый эскиз:

 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" несколько раз в вашем коде, они могут выделять такую ​​же память всем им. Теперь, если вы измените его, вы измените все из них!

ответил Nick Gammon 15 J000000Wednesday15 2015, 01:03:26
2

Пример:

 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 ожидает символ char * (который он может поэтому изменить), но вы передаете строковый литерал, который не следует изменять.

Компилятор предупреждает вас не делать этого. Будучи устаревшим, он может перейти от предупреждения к ошибке в будущей версии компилятора.


Решение. Сделайте 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.

ответил Nick Gammon 14 J000000Tuesday15 2015, 05:50:04
0

У меня есть эта ошибка компиляции:

TimeSerial.ino:68:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
   if(Serial.find(TIME_HEADER)) {

                         ^

Пожалуйста, замените эту строку:
#define TIME_HEADER "T" //Тэг заголовка для сообщения синхронизации времени по времени

с этой строкой:
#define TIME_HEADER 'T' //Тэг заголовка для сообщения синхронизации времени

и компиляция идет хорошо.

ответил gin 3 Jpm1000000pmSun, 03 Jan 2016 14:00:29 +030016 2016, 14:00:29

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132