Еще один простой и глупый вопрос о строках C++
Я сделал такой набросок:
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(9600);
char str1[64] = "test with spaces";
char str2[32] = "test with spaces";
Serial.println(str1);
Serial.println(str2);
if (str1 == str2) Serial.println("Equals");
else Serial.println("Different");
if (strcmp(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
// if (strcoll(str1, str2)) Serial.println("Equals"); // <-- это не скомпилируется для Arduino UNO { почему ??? }
// иначе Serial.println("Другой");
if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
else Serial.println("Different");
if (areEqual(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
strcpy(str1, "test+with+spaces");
strcpy(str2, "test with spaces");
Serial.println();
Serial.println(str1);
Serial.println(str2);
if (str1 == str2) Serial.println("Equals");
else Serial.println("Different");
if (strcmp(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
else Serial.println("Different");
if (areEqual(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
strcpy(str1, "test+with++++++++++++++++++++++++++++++++++++spaces");
strcpy(str2, "test with spaces");
Serial.println();
Serial.println(str1);
Serial.println(str2);
if (str1 == str2) Serial.println("Equals");
else Serial.println("Different");
if (strcmp(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
if (memcmp(str1, str2, sizeof(str2))) Serial.println("Equals");
else Serial.println("Different");
if (areEqual(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
}
void loop() {
// поместите сюда ваш основной код для многократного запуска:
}
bool areEqual(char* string1, char* string2) {
return ((strlen(string1) == strlen(string2)) && (strstr(string1, string2)));
}
Что производит это:
test with spaces
test with spaces
Different
Different
Different
Equals
test+with+spaces
test with spaces
Different
Equals
Equals
Different
test+with++++++++++++++++++++++++++++++++++++spaces
test with spaces
Different
Equals
Equals
Different
Первое сравнение глупо (==), я знаю. Он сравнивает адрес указателя, а не самой строки. Я просто поместил его, чтобы показать, как трудно программисту, который говорит на другом языке, понять такие вещи.
Второе сравнение (strcmp), как сказано в ссылке, «Сравнивает строку C str1 со строкой C str2.», НЕТ, это не так. Они абсолютно одинаковы, за исключением их заранее заданного размера. Но строки равны как мне кажется.
Третье сравнение (strcoll) использует локаль для сравнения двух строк, но почему они говорят разные, когда они равны?
Четвертое сравнение (memcmp), учитывая два указателя на одну и ту же последовательность символов, почему написано "разные"?
Самая умопомрачительная часть заключается в том, что сравнение "работает", когда вы добавляете столько "+", сколько хотите, только к одной из строк. Разве знак "+" тоже не символ?
Очевидно, что я упускаю что-то действительно важное в строках в стиле C++, но осмелюсь спросить: что это такое?
Спасибо.
@MrCabana, 👍1
Обсуждение2 ответа
Есть еще одна функция сравнения строк, которая может вам помочь strncmp()
void setup(){
Serial.begin(9600);
char str1[64] = "test with spaces";
char str2[32] = "test with spaces";
if(strncmp(str1, str2, 64) == 0){
Serial.println("strings match");
}
else{
Serial.println("strings do not match");
}
}
void loop(){}
Возвращаемое значение strcmp
не имеет логической семантики, как вы, кажется, ошибочно предполагаете.
strcmp
– это компаратор с тремя состояниями, который возвращает отрицательное, нулевое или положительное значение. Для равных строк он возвращает ноль, что означает, что сравнение на равенство с strcmp
обычно должно выглядеть следующим образом
if (strcmp(str1, str2) == 0) Serial.println("Equals");
else Serial.println("Different");
в то время как исходный код делает обратное.
Существует довольно распространенная некрасивая привычка писать такие сравнения, как
if (!strcmp(str1, str2)) Serial.println("Equals");
else Serial.println("Different");
(обратите внимание на применение оператора !
). Он работает правильно, но имеет плохую читабельность. Избегай это. Для компараторов с тремя состояниями гораздо лучше явно указать сравнение с 0
.
И вы допустили точно такую же ошибку с memcmp
. memcmp
также является компаратором с тремя состояниями, поэтому он должен быть
if (memcmp(str1, str2, sizeof str2) == 0) Serial.println("Equals");
else Serial.println("Different");
То же самое относится и к strcoll
.
PS И на самом деле такие строки с завершающим нулем, представленные массивами char[]
, называются строками в стиле C, а не строками в стиле C++.
Уххх. Вы молодцы. В конце концов, вокруг строк не было никаких мистических облаков, все дело было в результатах функций. Спасибо., @MrCabana
- Чтение строки, разделенной запятыми
- Проблемы с преобразованием byte[] в String
- Какие есть другие IDE для Arduino?
- Использование StringStream в скетче Arduino
- Плата для разработки STM8 с Arduino IDE
- Что именно делает возвращаемый тип в функции?
- Чтение и запись в EEPROM
- Все float возвращают округленное целое число в меньшую сторону.
Небольшое замечание по номенклатуре: строки вида
char *
называются "строками C" (будьте осторожны при поиске в гугле), строками с нулем или нулем в конце, поскольку они возникли в C. Напротив, строки C++ имеют типstd::строка
. С ними сравнение с==
работает так, как вы ожидаете: оно сравнивает строки, а не указатели., @Heinrich supports Monica