Перейти к содержанию
    

Си строки. Мир рухнул...

Вчера столкнулся с удивительным на мой взгляд явлением.

После переноса части исходников из рабочего проекта для 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Классический пример 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.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не понимаю зачем это сделано.

Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю

const char* str1 = "abc";

А когда не надо, то без const.

Логичнее некуда. Не согласны?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 minutes ago, demiurg_spb said:

Не понимаю зачем это сделано.

Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю

А когда не надо, то без const.

Логичнее некуда. Не согласны?

 

Логика в современном С++ ?

Да у вас даже функция не кошерно описана - теперь модно писать void foo(char s[10]) {....}, ну и референсы с амперсантами не забывать...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это не С++, а Си модуль подключенный к плюсатому проекту. Так что Ваше замечание не в тему. ИМХО. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 минут назад, demiurg_spb сказал:

Не понимаю зачем это сделано.

Ведь когда мне будет явно нужно сделать строку константной то я сам это и сделаю

Логичнее некуда. Не согласны?

Не согласны. Логично, что строковые литералы должны быть константами. Чтобы например printf("строка") занимало только 7 байт в RO-памяти, а не 7 байт в RO + 7 байт в ОЗУ.

А когда нужна явно не просто строка, а массив с начальной инициализацией строкой, то сами его и сделаете без проблем:

char string[] = "строка";

Так что - сделано правильно.

 

PS: И в Вашем примере:

const char* str1

str1 - это не сама строка, а указатель. Который сейчас указывает на строку, а через секунду - на что-то другое. Строка это: char const str[] = "...";

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну да. Палка о двух концах. Теперь исходники не так красиво будут выглядеть.

char str[] = "prog";
foo(str);

вместо

foo("prog");

Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции.

cprintf(const char*, ...) 

printf(char*, ...) 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, demiurg_spb said:

Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции.

cprintf(const char*, ...) 

printf(char*, ...) 

То есть количество функций мы умножим на два, чтобы не запутаться, а тип объекта будем выбирать исходя из того, к чему где-то привели указатель на него? Адъ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 минут назад, demiurg_spb сказал:

Но я всё равно против. Для решения указанных Вами задач я бы использовал две отдельные функции.

cprintf(const char*, ...) 

printf(char*, ...) 

Ну да. И потом сами же первый и наступите на эти широко разложенные грабли. Если даже в свою же функцию, объявленную как принимающую char *:

void foo(char* s)

передаёте char const * и не замечаете ошибки, то с такими правилами вообще бардак будет.

 

PS: Вам "Qt под linux" нашёл ошибку в вашем "рабочем проекте". Поблагодарите его и исправьте её. Я не свои правила изобретайте :king:

PPS: Плохо что си позволяет передачу литеральных строк в функции, принимающие аргумент char *. Лучше бы он ошибку выдавал. Но это уже как то обсуждали не так давно здесь.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, demiurg_spb сказал:

я бы использовал две отдельные функции.

cprintf(const char*, ...)

их и так уже вагон fprintf sprintf wprintf kprintf qdb_vmprintf vprintf vsprintf vfwprintf    swprintf fwprintf vsnprintf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

to: jcxz

Ничего страшного не будет.

Компилятор выдаст ошибку, что неявно const char* приводится к char* - это стандартное поведение.

Мне не ясно почему он мне не дал этого предупреждения (из примера в первом посте).

Он же знал что строковый литерал положит в RO и смолчал. 

 

А функций действительно будет больше в 2 раза. Печаль.

 

Я понял что так принято и ничего с этим уже не сделать. Понять и простить...

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, demiurg_spb сказал:

Ничего страшного не будет.

Компилятор выдаст ошибку, что неявно const char* приводится к char* - это стандартное поведение.

Где он такое выдаст??? Си как раз не выдаст ничего и молча приведёт char const * -> char *. Вот это как раз - плохо.

Но это поведение уже обсуждалось тут как-то несколько месяцев назад. Поищите тему.

 

Цитата

Мне не ясно почему он мне не дал этого предупреждения (из примера в первом посте).

Вот это то и плохо.... :sad:

вот, нашёл:  https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=141853&page=1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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)
          ~~~~~~^~~
 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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("..."), а Вы передаёте явно объявленный массив явно указанного типа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это правильный пример в контексте необходимости дублирования функций (const и не const) для достижения целей оптимизации.

Дайте ссылку что-ли на стандарт где хоть как-то упоминается о том что Си приводит  char const * -> char *.

Это нонсенс. ИМХО.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...