LINUX.ORG.RU

C, C++. Какова максимальная длина сишных строк (сегфолт на строке длиной ~640 Кб, GCC)?


0

4

Сейчас словил сегфолт при выводе строки длиной 636180 байт.

Сегфолтная команда:

fprintf(stderr, "%s", message);

где message имеет тип «const char *message» и размер данных в 636180 байт.

В стеке вызовов видно, что после функции fprintf() были вызваны:

strlen ()	
__GI__IO_fputs (str=0xb2379018 <Address 0xb2379018 out of bounds>, fp=0xb6ecc960 <_IO_2_1_stderr_>)

- т. е. сначала fputs(), последней strlen().

Сегфолт в дебрях strlen(). (Мне не нравится и строка с fputs(), ибо в ней «Address 0xb2379018 out of bounds»).

Таких проблем на коротких строках (чуть более 1000 знаков) не возникает.

Вопрос: существуют какие-то ограничения в компиляторах на работу с сишными строками? Я то думал, что размер строки ограничивается максимальным числом unsigned int. А тут вона как - 630 КБ прожевать не может.

Или, к примеру, существует какое-то ограничение на работу с потоком ошибок, только я о нем не знаю?

Если это важно: gcc (Debian 4.7.1-7) 4.7.1

★★★★★

Ноль в конец строки допиши.

Как ты собираешь такую огромную строку? Вангую говнокод с миллионом объединений.

ziemin ★★
()

fprintf(stderr, «%s», message);

казалось бы, зачем тут флаги форматирования, когда твое 640КБ-полотно всё равно не форматируется. Писал бы fwrite-ом :)

yoghurt ★★★★★
()
Ответ на: комментарий от Xintrea

Покажи фрагменты кода: как создаёшь строку, как её собираешь, все объявления задействованных переменных.

ziemin ★★
()
Ответ на: комментарий от yoghurt

казалось бы, зачем тут флаги форматирования, когда твое 640КБ-полотно всё равно не форматируется. Писал бы fwrite-ом :)

Через fwrite() такая же фигня.

printf("Len of line: %d\n", messageLen);
fwrite(message, sizeof(char), messageLen, stderr);

Размер строки показывает в логе, на fwrite() имеем сегфолт.

Len of line: 636228

Я склоняюсь к мысле, что таки ограничение stderr.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от ziemin

Или, к примеру, существует какое-то ограничение на работу с потоком ошибок, только я о нем не знаю?

И как ты это выводишь тоже покажи.

ziemin ★★
()
Ответ на: комментарий от ziemin

Полный фрагмент с fwrite(), msg - это QString от Qt:

   const char *message=msg.toLocal8Bit().data();
   unsigned int messageLen=msg.toLocal8Bit().size();
   printf("Len of line: %d\n", messageLen);
   fwrite(message, sizeof(char), messageLen, stderr);
Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Я не могу в Qt вызвать qDebug() в этом месте, потому что это место - есть переопределенная функция qDebug().

Поэтому выводить нужно через стандартные сишные механизмы.

Тестовая строка имееет только ASCII символы, так что на toLocal8Bit() можно не грешить.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от ziemin

unsigned int

Это гораздо меньше, чем 640к.

O_o


Qt держит строки больше 65к? Скорее всего нет. Так что это их ограничение.

Нигде про такое ограничение не написано. И в других частях программы QString переваривает и поболя строки.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Begemoth

Марш читать Страуструпа на тему времени жизни объектов.

Теоретик в треде. Заигнорить тебя, читоли?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от ziemin

Попробуй вывести не message, а msg.toLocal8Bit().data(), как указали выше.

Хоть один вменяемый нормальным языком выражается.

Заработало, спасибо.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Это перефразированный совет Begemoth, так что всё равно отправляйся читать. :)

ziemin ★★
()
Ответ на: комментарий от Begemoth

А мне и не нужно понимать, авторы синтаксиса C/C++ ничего не сделали для улучшения понимания их языка. Была бы альтернатива - пользовался чем-нибудь другим, но пока ее нет - будем пользовать язык как средство.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Дело не в синтаксисе, а в библиотеке. .data() возвращает (и не только в Qt, а например в stl тоже, временный указатель)

ziemin ★★
()
Ответ на: комментарий от ziemin

Ошибся, но не во всём. Стандарт С++ указывает, что диапазон значений int - от INT_MIN до INT_MAX (сноска в разделе 3.9.1), беря эти константы из библиотеки С (раздел C.3). Стандарт С же требует (пункт 5.2.4.2.1) чтобы INT_MIN и INT_MAX по абсолютной величине были не менее 32767. Так что int - минимум 2 байта, минимум 4 байта - это long.

Begemoth ★★★★★
()
Ответ на: комментарий от sergijoo

Ты мне ещё про битовые типы в компиляторах C для всяких PIC-ов расскажи. Разработчики компиляторов для такой мелочи на полное соответствие стандарту вполне резонно забивают.

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

Я просто имел дело с int 2 байта, так что знаю :)

ziemin ★★
()
Ответ на: комментарий от ziemin

Да понятно.

В других языках типа PHP с этим делом попроще, а в Ассемблере - хотя бы наиболее явно. И только в C/C++ сделано самым неочевидным образом. Прикольно, конечно, что значение теряется сразу после получения ссылки на него, если конечно ты не завернул его в вызов по стеку. Но с точки зрения здравого смысла - это издевательство над программистом: выдавать ему ссылку и не гарантировать что ссылка в следующей же команде будет указывать на корректный объект.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Begemoth

С тут, кстати, ни при чём, но ты неспособен понять даже этого.

Ты неспособен понять, что все эти низкоуровневые пляски мало кого уже интересуют. Языки развиваются, и если бы не аппаратные ограничения, то C/C++ уже давно были на свалке истории как недоразумение.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

И только в C/C++ сделано самым неочевидным образом.

Ну не скажи. Как я уже выше говорил это поведение библиотек. Т.е. с точки зрения компилятора C/C++ ты присвоил указатель переменной, а потом его использовал. Он сам ничего бы не соптимизировал бы.

Не проблема C/C++, что к этому моменту указатель недействителен из-за действий библиотеки.

Кстати я тоже считаю такое поведение дурацким, но необходимым. Моглибы назвать функцию не .data(), а, допустим, temporaryData()

ziemin ★★
()
Последнее исправление: ziemin (всего исправлений: 1)
Ответ на: комментарий от Xintrea

Есть вещи, которые Qt гарантирует и на которые можно полагаться. Достаточно прочитать документацию и исходники Qt. Судя по твоему сообщению ты думаешь, что Qt удаляет или инвалидирует значение сразу после вызова. Это не так и, более того, я даже не представляю, как это можно было бы сделать. Задачу ты решил, но как решил - не понял. Много проблем перед тобой ещё встанет с таким подходом.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от Legioner

Достаточно прочитать документацию

Извиняюсь, у меня туго с английским.

и исходники Qt.

Не был бы ты синей лошадью...

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

и исходники Qt.

Не был бы ты синей лошадью...

А что тут то не так? Не понимаешь английский, но уж С++ то хотя бы должен понимать? В Qt есть недостатки, но нечитаемый код к ним не относится.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Судя по твоему сообщению ты думаешь, что Qt удаляет или инвалидирует значение сразу после вызова. Это не так и, более того, я даже не представляю, как это можно было бы сделать. Задачу ты решил, но как решил - не понял.

Мне очень нравится такой стиль разговора ни о чем.

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

Либо пиши предметно, либо я продолжу тебя называть синей лошадью.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Нет, это я не внимательно код прочитал, проехали :) Указатель действительно инвалидируется после statement-а и его надо или использовать на месте или отдельно объявлять переменную QData и тогда она будет жить сколько нам надо.

Legioner ★★★★★
()
Ответ на: комментарий от Xintrea

все эти низкоуровневые пляски мало кого уже интересуют

Это не низкоуровневые пляски, это семантика языка, и знать её необходимо для языка любого уровня. Вот к примеру на высокоуровневом питоне:

class Foo(QWdiget):
  ...

def bar()
  f = Foo()
  f.show()

bar()

работает образом не очевидным для человека, которого не интересуют «низкоуровневые пляски».

Языки развиваются, и если бы не аппаратные ограничения, то C/C++ уже давно были на свалке истории как недоразумение.

Не только и не столько аппаратные ограничения. Тонны кода уже написанного на С и C++, в том числе библиотек, никак не способствуют переезду этих языков на свалку, как ни печально.

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

работает образом не очевидным для человека, которого не интересуют «низкоуровневые пляски».

Я не знаю питон. В этом примере не будет вызван метод show() объекта f?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Begemoth

это семантика языка

Да нет же. Язык тут не причём. Никакой компилятор не уничтожит переменную, зная, что она используется. Это хитрое поведение внутри библиотеки.

Тут дело в том, что был выбор: или создавать постоянный объект для data() или написать в руководстве, что доверять указателю вне выражения ни в коем случае нельзя.

Разработчики пошли вторым путём чтобы избежать колоссальных утечек памяти.

Рано или поздно ТС научится отличать библиотеки от языка и начнёт изучать документацию.

ziemin ★★
()
Ответ на: комментарий от Begemoth

Тонны кода уже написанного на С и C++, в том числе библиотек, никак не способствуют переезду этих языков на свалку, как ни печально.

Переезжать то тоже некуда.

mashina ★★★★★
()
Ответ на: комментарий от Xintrea

если бы не аппаратные ограничения, то C/C++ уже давно были на свалке истории

LOL

false ★★★★★
()
Ответ на: комментарий от ziemin

Да нет же. Язык тут не причём. Никакой компилятор не уничтожит переменную,
зная, что она используется. Это хитрое поведение внутри библиотеки.

А библиотека уничтожит? :) Какая она плохая. Может все таки язык?

anonymous
()
Ответ на: комментарий от anonymous

Если указатель становится недействительным из-за манипуляций внутри библиотеки, пускай и compile-time, то библиотека.

С точки зрения синтаксиса происходит присваивание указателя переменной, а потом использование этой переменной. Любые скрытые действия на совести создателя библиотеки.

Вообще своё мнение я уже выше указал.

ziemin ★★
()
Ответ на: комментарий от ziemin

Выше уже писали, зачем повторяться.

anonymous
()
Ответ на: комментарий от anonymous

Никогда больше не программируй. Не твое это.

Ты хотел сказать «Никогда больше не программируй на C/C++». Я это знаю.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

И снова fail, это фиолетовый цвет.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.