Недопустимое преобразование из 'char' в 'const char*' [-fpermissive] в строке
Я компилирую какой-то код, который не писал, и он взрывается сообщением об ошибке
invalid conversion from 'char' to 'const char*' [-fpermissive]
на линии
if (loginPassword == '\0') loginPassword = "";
Я не понимаю, почему эта строка отличается от предыдущих строк, и все ответы, которые я могу найти, связаны с переменными, начинающимися как char.
Что не так с этим кодом и как его исправить?
void saveUnit(String tempUnit, String supportMode, String loginPassword, String minTemp, String maxTemp, String tempStep) {
const size_t capacity = JSON_OBJECT_SIZE(6) + 200;
DynamicJsonDocument doc(capacity);
// если единица измерения температуры пуста, мы используем по умолчанию цельсий
if (tempUnit == '\0') tempUnit = "cel";
doc["unit_tempUnit"] = tempUnit;
// если minTemp пуст, мы используем значение по умолчанию 16
if (minTemp == '\0') minTemp = 16;
doc["min_temp"] = minTemp;
// если maxTemp пуст, мы используем значение по умолчанию 31
if (maxTemp == '\0') maxTemp = 31;
doc["max_temp"] = maxTemp;
// если tempStep пуст, мы используем значение по умолчанию 1
if (tempStep == '\0') tempStep = 1;
doc["temp_step"] = tempStep;
// если режим поддержки пуст, мы используем режим по умолчанию все
if (supportMode == '\0') supportMode = "all";
doc["support_mode"] = supportMode;
// если пароль для входа пуст, мы используем пустой
if (loginPassword == '\0') loginPassword = "";
doc["login_password"] = loginPassword;
File configFile = SPIFFS.open(unit_conf, "w");
if (!configFile) {
// Serial.println(F("Не удалось открыть конфигурационный файл для записи"));
}
serializeJson(doc, Serial);
serializeJson(doc, configFile);
configFile.close();
}
@Ben Dauphinee, 👍1
Обсуждение1 ответ
Лучший ответ:
Независимо от приведенных ниже результатов, вы действительно не хотите сравнивать строковый объект с нулевым символом таким образом (подробнее об этом ниже). На самом деле что-то вроде: if (someArduinoStringObj.isEmpty ()) {
- лучшая идея, независимо от того, на каком ядре вы находитесь.
Поэтому для любого, кто попал сюда с этой проблемой с кодом, который работал и больше не работает, ответ в основном таков: не делайте этого; вероятно, не следовало этого делать в первую очередь.
Если вам интересно, что я нашел, то ниже есть материал на эту тему.
Так что у меня нет полного представления об этом, но мне есть о чем доложить. Когда мы начали проходить через это, я не думал, что в пакетах поддержки платы Arduino будет что-то, что повлияет на это, но оказалось, что это не так.
Мы выяснили, что в версии ESP8266 Arduino core 3.0.0 строки следующей формы не компилируются, а в версии 2.7.4 компилируются без ошибок. Здесь, под 3.0.0, он не был придирчив к конкретному loginPassword
.
if (someArduinoStringObj == '\0') someArduinoStringObj = "some literal";
Это можно абстрагировать до несколько бессмысленного:
someArduinoStringObj == '\0';
Поскольку именно эта часть имеет значение. Я действительно думал, что в этом мире происходит что-то более умное. WString.h/WString.cpp код, дополнительный конструктор или неявный вызов оператора преобразования перед кодом для оператора==. Существует явный конструктор для String
, который принимает один символ, но он просто явный; он не принимает участия в вычислении приведенного выше выражения==. И нет автоматического преобразования
строки
в const char *
. Оказывается, в классе String нет ничего умного, когда дело доходит до этой проблемы. На самом деле вы можете свести это к чему-то подобному, так что сам класс String на самом деле вообще не задействован:
void func(const char *) {}
void setup() {
func('\0');
}
// ...
Это также пройдет компиляцию в версии 2.7.4 и завершится неудачей с аналогичным сообщением об ошибке в версии 3.0.0. Таким образом, со строкой он просто пытается вызвать оператор==(const char *)
, даже если ему присваивается тип char. Прежде чем приступить к этому, я проверил теорию, которая заключалась в том, чтобы выяснить, что произойдет, если дать
== '\1';
или == 'X')
и т.д., Любое ненулевое значение, потому что 0 имел интересную связь с указателями в C++ и C. Это имеет больше смысла, как только вы поймете, что в String.h происходит что-то особенное. Мы в основном говорим о func('\0')
против func('\1')
или func('X')
Ну, в 2.7.4 эти значения терпят неудачу там, где '\0' нет, но под 3.0.0 оба терпят неудачу. Поэтому я занялся изучением platform.txt файл на обеих основных версиях, думая, что, может быть, я замечу разницу в параметрах компилятора. Например, это имело бы "смысл", если бы в 2.7.4 был-fpermissive
, а в 3.0.0-нет, но это не так. Основное различие заключается в том, что 3.0.0 имеет-std=g++17, а 2.7.4-std=g++11. Просто для того, чтобы, черт возьми, я украл командную строку из подробного вывода компиляции для .ino.cpp файл и заменил -std=g++17 на-std=g++11 и применил его к урезанному файлу; это не имело никакого значения. Итак, насколько я понимаю, существует некоторая разница в параметрах по умолчанию, указанных между двумя версиями компилятора, используемыми в двух версиях пакета esp8266.
Постоянные выражения, которые вычисляются до нуля типа int
(по крайней мере), преобразуются в константы нулевого указателя. У меня не было привычки использовать символьные ('\0'
) константы с нулевым значением для нулевых указателей, и я не копался в различных изданиях стандарта C++, чтобы увидеть, что каждый из них может сказать о них; в любом случае это меня не удивило. Но в любом случае, это в основном то, что происходит здесь: строковый объект сравнивается с константой нулевого указателя, по крайней мере, когда он компилируется. И если это заставит тебя сойти с ума, что ж, я тоже. Если вы последуете этому примеру, то в конечном итоге окажетесь здесь:
unsigned char String::equals(const char *cstr) const {
if (len() == 0)
return (cstr == NULL || *cstr == 0);
if (cstr == NULL)
return buffer()[0] == 0;
return strcmp(buffer(), cstr) == 0;
}
Таким образом, грубо говоря, someArduinoString == '\0'
, где он будет компилироваться, эквивалентен someArduinoString == nullptr
, который имеет тот же эффект, что и someArduinoString == ""
. Итак, то, что вы видите, не совсем неявная форма someArduinoString == String('\0')
.
Я не могу представить, что хочу сказать someArduinoString == '\0'
над someArduinoString.isEmpty ()
, но с точки зрения того, почему он не работает на 3.0.0, я все еще не уверен. Я могу сказать вам, что это произойдет, если вы посадите-fpermissive
в platform.txt но на самом деле это ничего не объясняет. Когда-нибудь, когда мне будет очень скучно, я посмотрю, что на самом деле говорит языковой стандарт и какие версии g++ делали то, что под какими опциями.
Даже если бы я это понял, мой ответ все равно звучал бы так: не делай этого.
- Проблемы с преобразованием byte[] в String
- Ошибка компиляции для платы Arduino Nano
- Ошибка компиляции для любой платы arduino ide 1.8.9
- Чтение из SPIFFS - Как лучше всего работать со строковым (или char) массивом с неопределенной длиной?
- Что мне делать с StackOverflow при ошибке компиляции?
- Чтение и запись в EEPROM
- UECIDE: ошибка компоновщика с библиотекой U8g2
- Не удалось скомпилировать библиотеки c++11, несмотря на добавление-std=c++11 в platform.txt
Я предполагаю, что это было скопировано из контекста, где
loginPassword
был указателем, а неString
, где его, вероятно, действительно следовало сравнить сnullptr
или0
в зависимости от эпохи C++., @timemage@timemage https://github.com/gysmo38/mitsubishi2MQTT/blob/master/src/mitsubishi2mqtt/mitsubishi2mqtt.ino, @Ben Dauphinee
. Если это исходный контекст, то я понятия не имею, почему он когда - либо компилировался. Вы не получаете ту же ошибку для "supportMode" и других, которые следуют этому же шаблону?, @timemage
Правильно, это первая строка, которая обрывается. Я не могу понять, почему, когда он должен сломаться до этого., @Ben Dauphinee
Вполне вероятно, что все, что следует шаблону "if (X = = `\0') X = some_default;", должно было быть написано " if (X=="")"... или, может быть, более эффективно " if (X. length() == 0)"..., но это своего рода нонсенс для поля loginPassword. Если она уже пуста... Она пуста., @timemage
Хорошо, если я запущу компиляцию arduino-cli против esp32:esp32:esp32 FQBN с минимальными лесами вокруг вашего кода, например, включая ArduinoJson.h, SPIFFS.h, пустой цикл и настройку, он компилируется без ошибок. Ядро esp32, которое находится на моей машине, 1.0.4, вероятно, старое, но это то, что у меня есть. ArduinoJson был версии 6.18.0., @timemage
Та же версия ArduinoJson, компилируемая против esp8266, @Ben Dauphinee
Давайте [продолжим это обсуждение в чате](https://chat.stackexchange.com/rooms/126427/discussion-between-timemage-and-ben-dauphinee)., @timemage