Czy źle jest deklarować ciąg w stylu C bez const? Jeśli tak, to dlaczego?

Robienie tego w C++

char* cool = "cool";

Kompiluje dobrze, ale daje mi Ostrzeżenie:

Przestarzała konwersja ze stałej łańcuchowej na znak*.

Nigdy nie użyłbym celowo ciągu W Stylu C nad std::string, ale na wszelki wypadek, gdyby zadano mi to pytanie:

Czy błędną praktyką jest deklarowanie ciągu w stylu C bez modyfikatora const? Jeśli tak, to dlaczego?

 63
Author: Maraboc, 2016-07-25

8 answers

Tak, ta deklaracja jest złą praktyką, ponieważ pozwala na wiele sposobów przypadkowego wywołania niezdefiniowanego zachowania przez zapisanie do literału łańcuchowego, w tym:

cool[0] = 'k';
strcpy(cool, "oops");

Z drugiej strony, jest to całkowicie w porządku, ponieważ przydziela nie-const tablicę znaków:

char cool[] = "cool";
 58
Author: aschepler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 17:40:50

Tak, W C++ należy zawsze odnosić się do literałów łańcuchowych ze zmiennymi typu const char * LUB const char [N]. Jest to również najlepsza praktyka przy pisaniu nowego kodu C.

Literały łańcuchowe są przechowywane w pamięci tylko do odczytu, jeśli jest to możliwe; ich typ jest odpowiednio const-kwalifikowany. C, ale nie c++, zawiera wartę kompatybilności wstecznej, w której kompilator nadaje im typ char [N] nawet jeśli są przechowywane w pamięci tylko do odczytu. Jest to spowodowane tym, że literały string są starsze niż const Kwalifikacje. const został wynaleziony w okresie poprzedzającym to, co obecnie nazywa się " C89 "- wcześniejsza forma języka "K & R" nie miała go.

Niektóre kompilatory C zawierają opcjonalny tryb, w którym wyłączona jest kompatybilność wsteczna, a char *foo = "..."; zapewni Ci taką samą lub podobną diagnostykę, jak w C++. GCC oznacza ten tryb -Wwrite-strings. Bardzo polecam go dla nowego kodu; jednak włączenie go dla starego kodu może wymagać ogromnej ilości scutwork za bardzo mało korzyści.

 16
Author: zwol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 19:36:20

Jest źle. Jest bardzo źle. Do tego stopnia, że nie jest to już możliwe w C++11.

Modyfikowanie pamięci literału łańcuchowego jest niezdefiniowanym zachowaniem.

 14
Author: milleniumbug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 17:39:29

Po pierwsze, {[0] } nie jest standardem C++. Literał Łańcuchowy ma typ const char[n]. Tak więc powyższy wiersz kodu łamie const-poprawność i nie powinien być kompilowany. Niektóre Kompilatory, takie jak GCC zezwalają na to, ale wydają Ostrzeżenie, ponieważ jest to wstrzymanie od C. MSVC wyda błąd, ponieważ jest to błąd.

Po drugie, dlaczego nie pozwolić kompilator pracować dla Ciebie? Jeśli jest on oznaczony const wtedy pojawi się ładny błąd kompilatora, jeśli przypadkowo spróbujesz go zmodyfikować. Jeśli tego nie zrobisz, możesz uzyskać naprawdę paskudny czas pracy błąd, który może być znacznie trudniejszy do znalezienia.
 13
Author: NathanOliver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 14:30:18

Jest to złe, ponieważ stałe łańcuchowe mogą być zawarte tylko raz na binarne (słowo kluczowe: stringtable, .strtab). Np. w

char *cool = "cool";
char *nothot = "cool";

Obie zmienne mogą wskazywać na to samo miejsce pamięci. Modyfikowanie zawartości jednego z nich może zmienić również drugi, tak aby po

strcpy(nothot, "warm");

Twoje cool staje się "ciepłe".

W skrócie, jest to nieokreślone zachowanie.

 7
Author: ensc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 10:09:17

Jest to literał Łańcuchowy, dlatego powinien być stały, ponieważ pamięć może znajdować się w sekcji Tylko do odczytu. Jeśli masz char cool[] = "cool"; to nie jest to problem, pamięć jest twoja.

 6
Author: KIIV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 17:40:32

Char * cool = "cool"

"cool" będzie przechowywane w bloku tylko do odczytu (zazwyczaj w segmencie danych), który jest współdzielony między funkcjami. Jeśli spróbujesz zmodyfikować łańcuch "cool" przez punkt cool, pojawi się błąd, taki jak segment error, gdy program jest uruchomiony. Jeśli użyjesz const char* cool = "cool", pojawi się błąd podczas kompilacji, jeśli spróbujesz zmodyfikować łańcuch znaków.
Możesz przeczytać tę stronę, aby uzyskać więcej informacji http://www.geeksforgeeks.org/storage-for-strings-in-c/

 2
Author: zhangke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 06:27:02

Jest to dobra praktyka, aby napisać const dla ciągów (zwłaszcza, gdy używane ciąg dosłowny), ale w C to prawie nie robi różnicy, rzuci Ci ostrzeżenie w c++, ale nie ma ostrzeżenia W c, również pamiętać, niektóre Kompilatory zakładają .rozszerzenie c po prostu jako C ale .C jak c++, więc bądź ostrożny w takich punktach.w przeciwnym razie dobrą praktyką jest używanie const z przypadku łańcuchów, więc przez pomyłkę nie zmieniasz ciągu lub próbujesz zmienić ciąg znaków, który jest przechowywany w pamięci tylko do odczytu.

 0
Author: Noshiii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 23:00:39