Нужны ли переменные cstring статическими для работы с ESP8266?

Вопрос или проблема

Несмотря на 5 лет разработки с ESP8266 (mini D1), я все еще в замешательстве:
Версия моей IDE – 1.8.19
Мой сценарий содержит 3300 строк, но я создал тестовый случай:
Это сценарий:

// Глобальные переменные
int i=1;

void setup() {
  // поместите ваш код настройки сюда, чтобы он выполнялся один раз:
  Serial.begin(115200);
  delay(1000);
  Serial.println();
  Serial.println("Небольшой тест...");
  Serial.println("Случай 1");
}

void test() {
  char* essai = "Hello my wolrd";    // (1) Это не переназначает essai на значение каждый раз!
  // static char essai[50] = {0};    // (2) Это работает как статический, так и нет!!!!!
  // char* essai = "Hello my wolrd"; // (3) Это не работает, как ожидалось
  // strcpy(essai, "Hello my wolrd");// (4)
  Serial.printf("essai 1='%s'\n",essai);
  strcpy(essai,"Hello your wolrd"); // ваш мир
  Serial.printf("essai 2='%s'\n",essai);
}

void loop() {
  // поместите ваш основной код сюда, для повторного выполнения:
  if (i < 4) {  // то есть 3 раза
    Serial.printf("Тест %d...\n",i);
    test();
  }
  if (i == 4) {
    Serial.println("Тест завершен");
  }
  i++;
  delay(1000);
}

Я ожидал, что результаты будут напечатаны три раза с 2 разными строками, но смотрите:
результаты:

    Небольшой тест...
    Случай 1 активная линия: 1
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello your wolrd'
    essai 2='d'
    Тест 3...
    essai 1='d'
    essai 2='d'
    Тест завершен
    
    Небольшой тест...
    Случай 2 активные линии: 1,4
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello your wolrd'
    essai 2='d'
    Тест 3...
    essai 1='d'
    essai 2='d'
    Тест завершен
    
    Небольшой тест...
    Случай 3 активная линия: 2
    Тест 1...
    essai 1=''
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello your wolrd'
    essai 2='Hello your wolrd'
    Тест 3...
    essai 1='Hello your wolrd'
    essai 2='Hello your wolrd'
    Тест завершен
    
    Небольшой тест...
    Случай 4  активные линии: 2,4 ==> результат, как ожидалось
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 3...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест завершен
    
    
    Небольшой тест...
    Случай 5 активная линия: 3
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello your wolrd'
    essai 2='d'
    Тест 3...
    essai 1='d'
    essai 2='d'
    Тест завершен
    
    Небольшой тест...
    Случай 6 активные линии: 3,4 
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello your wolrd'
    essai 2='d'
    Тест 3...
    essai 1='d'
    essai 2='d'
    Тест завершен
    
    Небольшой тест...
    Случай 7  активные линии: 2 (строка 2 больше не статическая) результат, как ожидалось
    Тест 1...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 2...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест 3...
    essai 1='Hello my wolrd'
    essai 2='Hello your wolrd'
    Тест завершен

Это нормально, что

char* essai="Hello my world"; 

не работает, как я ожидал?
(Извините за ошибку в написании слова World).

Ответ или решение

Вопрос о том, нужно ли объявлять переменные типа cstring как статические (static) для работы с ESP8266, затрагивает основы работы с указателями и строками в языке C/C++. Давайте разберемся, почему ваш код ведет себя именно так.

Объяснение поведения кода

  1. Строковые литералы и указатели:
    Когда вы пишете:

    char* essai = "Hello my wolrd";

    Вы при этом объявляете указатель essai, который указывает на строковый литерал в памяти. Строковые литералы являются неизменяемыми, и попытка изменить их приведет к неопределенному поведению. Именно поэтому в последующих вызовах, когда вы пытаетесь изменить essai, возникает проблема. Например,:

    strcpy(essai, "Hello your wolrd"); // Приведет к ошибке
  2. Статические массивы:
    Следующий код:

    static char essai[50] = {0};

    создает статический массив символов, который инициализируется нулями. Вы можете использовать strcpy для копирования строки в этот массив, и он будет сохраняться между вызовами функции test(). Статическая переменная сохраняет свое значение между вызовами функции:

    strcpy(essai, "Hello your wolrd"); 
  3. Необъявленные локальные переменные:
    Если вы используете локальную переменную char* essai, как в следующем:

    char* essai = "Hello my wolrd";

    то каждый раз, когда происходит вызов функции test, вы заново объявляете указатель, который снова будет указывать на неизменяемый строковый литерал. Поэтому до тех пор, пока вы не используете strcpy, переменная будет каждый раз указывать на один и тот же литерал.

Почему у вас возникают проблемы

  1. В случае (1) вы пытаетесь работать с неизменяемым строковым литералом, что приводит к неопределенному поведению, когда вы пытаетесь его изменить.
  2. В случае (2) и (4), когда вы используете статический массив, все работает, так как память выделяется для вашего массива, и вы можете изменять его содержимое без последствий.
  3. Пример (3) ведет себя как и в (1), так как строковый литерал также остается неизменным и при каждом вызове функции происходит новое объявление указателя.

Рекомендации

  • Если вы хотите работать со строками, которые могут изменяться, лучше использовать массивы символов (как в случае с static char essai[50]) вместо указателя на строковый литерал.
  • Если размер вашей строки заранее известен и не изменяется, вы можете объявить его как static, чтобы сохранить состояние между вызовами.
  • Для удобства и избежания путаницы рекомендуется использовать std::string (если ваша среда поддерживает C++), что значительно упростит работу со строками.

Заключение

Ваша путаница связана с особенностями работы с указателями и строковыми литералами в C/C++. Использование статических массивов обеспечивает правильное функционирование вашего кода, и вам не обязательно использовать static, если вы хотите просто сохранить значение. Однако при работе с указателями на неизменяемые строковые литералы следует обязательно избегать их изменения, чтобы избежать ошибок в программе.

Оцените материал
Добавить комментарий

Капча загружается...