demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Вчера столкнулся с удивительным на мой взгляд явлением. После переноса части исходников из рабочего проекта для bare-metal embedded в проект Qt под linux неожиданно стал появляться SEGMENTATION FAULT. После недолгой отладки выяснил что падает при попытке записи байта в строку (прошу заметить не константную строку!!!). void foo(char* s) { s[4] = '\0'; } foo("prog"); // segmentation fault inside! Погуглил, оказалось вот в чём причина. Я выпал в осадок... https://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string-initialized-with-cha Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 61 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Классический пример UB, все, наверное, рано или поздно наступают. Quote char s[] = "abc", t[3] = "abc"; defines ‘‘plain’’ char array objects s and t whose elements are initialized with character string literals. This declaration is identical to char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' }; The contents of the arrays are modifiable. On the other hand, the declaration char *p = "abc"; defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Не понимаю зачем это сделано. Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю const char* str1 = "abc"; А когда не надо, то без const. Логичнее некуда. Не согласны? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_4afc_ 24 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 7 minutes ago, demiurg_spb said: Не понимаю зачем это сделано. Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю А когда не надо, то без const. Логичнее некуда. Не согласны? Логика в современном С++ ? Да у вас даже функция не кошерно описана - теперь модно писать void foo(char s[10]) {....}, ну и референсы с амперсантами не забывать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Это не С++, а Си модуль подключенный к плюсатому проекту. Так что Ваше замечание не в тему. ИМХО. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 182 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 16 минут назад, demiurg_spb сказал: Не понимаю зачем это сделано. Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю Логичнее некуда. Не согласны? Не согласны. Логично, что строковые литералы должны быть константами. Чтобы например printf("строка") занимало только 7 байт в RO-памяти, а не 7 байт в RO + 7 байт в ОЗУ. А когда нужна явно не просто строка, а массив с начальной инициализацией строкой, то сами его и сделаете без проблем: char string[] = "строка"; Так что - сделано правильно. PS: И в Вашем примере: const char* str1 str1 - это не сама строка, а указатель. Который сейчас указывает на строку, а через секунду - на что-то другое. Строка это: char const str[] = "..."; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Ну да. Палка о двух концах. Теперь исходники не так красиво будут выглядеть. char str[] = "prog"; foo(str); вместо foo("prog"); Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции. cprintf(const char*, ...) printf(char*, ...) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 61 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 8 minutes ago, demiurg_spb said: Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции. cprintf(const char*, ...) printf(char*, ...) То есть количество функций мы умножим на два, чтобы не запутаться, а тип объекта будем выбирать исходя из того, к чему где-то привели указатель на него? Адъ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 182 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 15 минут назад, demiurg_spb сказал: Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции. cprintf(const char*, ...) printf(char*, ...) Ну да. И потом сами же первый и наступите на эти широко разложенные грабли. Если даже в свою же функцию, объявленную как принимающую char *: void foo(char* s) передаёте char const * и не замечаете ошибки, то с такими правилами вообще бардак будет. PS: Вам "Qt под linux" нашёл ошибку в вашем "рабочем проекте". Поблагодарите его и исправьте её. Я не свои правила изобретайте PPS: Плохо что си позволяет передачу литеральных строк в функции, принимающие аргумент char *. Лучше бы он ошибку выдавал. Но это уже как то обсуждали не так давно здесь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
megajohn 3 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 11 минут назад, demiurg_spb сказал: я бы использовал две отдельные функции. cprintf(const char*, ...) их и так уже вагон fprintf sprintf wprintf kprintf qdb_vmprintf vprintf vsprintf vfwprintf swprintf fwprintf vsnprintf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба to: jcxz Ничего страшного не будет. Компилятор выдаст ошибку, что неявно const char* приводится к char* - это стандартное поведение. Мне не ясно почему он мне не дал этого предупреждения (из примера в первом посте). Он же знал что строковый литерал положит в RO и смолчал. А функций действительно будет больше в 2 раза. Печаль. Я понял что так принято и ничего с этим уже не сделать. Понять и простить... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 182 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 11 минут назад, demiurg_spb сказал: Ничего страшного не будет. Компилятор выдаст ошибку, что неявно const char* приводится к char* - это стандартное поведение. Где он такое выдаст??? Си как раз не выдаст ничего и молча приведёт char const * -> char *. Вот это как раз - плохо. Но это поведение уже обсуждалось тут как-то несколько месяцев назад. Поищите тему. Цитата Мне не ясно почему он мне не дал этого предупреждения (из примера в первом посте). Вот это то и плохо.... вот, нашёл: https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=141853&page=1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 7 minutes ago, jcxz said: Где он такое выдаст??? Си как раз не выдаст ничего и молча приведёт char const * -> char *. void foo(char* str) {puts(str);} void cfoo(const char* str) {puts(str);} int main(void) { const char str[] = "123"; // const char* str = "123"; // так тоже самое foo(str); cfoo(str); return 0; } test_const.c: In function ‘main’: test_const.c:20:6: warning: passing argument 1 of ‘foo’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] foo(str); ^~~ test_const.c:5:16: note: expected ‘char *’ but argument is of type ‘const char *’ void foo(char* str) ~~~~~~^~~ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 182 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба 3 минуты назад, demiurg_spb сказал: test_const.c: In function ‘main’: test_const.c:20:6: warning: passing argument 1 of ‘foo’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] Пример некорректный. Разговор шёл о foo("..."), а Вы передаёте явно объявленный массив явно указанного типа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 11 июля, 2019 Опубликовано 11 июля, 2019 · Жалоба Это правильный пример в контексте необходимости дублирования функций (const и не const) для достижения целей оптимизации. Дайте ссылку что-ли на стандарт где хоть как-то упоминается о том что Си приводит char const * -> char *. Это нонсенс. ИМХО. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться