LINUX.ORG.RU

Баг cin в mingw. Как бороться?

 ,


0

1

Наваял несложную консольную прогу. Пока ваял всё было ок. Решил потестить на винде. Внезапно, глючит! По всей видимости, виноват баг реализации cin в mingw 4.7.0.

Вот минимальный код, на котором проявляется баг:


#include <iostream>
#include <string>
using namespace std;

int main(void)
{
string x;
cin>>x;
return 0;
}

Суть бага: если ввести несколько букв, затем ctrl+Z, затем опять буквы, затем Enter, то ввод начнётся заново на следующей строчке

★★★★★

Сомневаюсь, что это баг. ctrl+z может просто не иметь специального значения, если не является последним символом в строке.

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

ctrl+z == EOF. если cin встречает EOF, то он, по хорошему, обязан остановить чтение. кстати, на онтопике он так и поступает.

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

ctrl+z == EOF

Это если cin открыт в текстовом режиме, не уверен, что это гарантируется.

В общем случае, это ведь должно быть на совести командной оболочки (или, возможно, самого терминала). Ничего относящегося к ctrl-z/ctrl-d в описании стандартной библиотеки я не встречал, отсюда и сомнения в наличии бага.

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

может косяк и в терминале, я хз. как бороться-то?

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

по идее, что делать с ЕОФ решает именно cin, хотя хз точно

Ничего относящегося к ctrl-z/ctrl-d в описании стандартной библиотеки

как же? про ЕОФ там очень даже пишут

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

как же? про ЕОФ там очень даже пишут

Я имел в виду упоминаний, что ctrl-z должно трактоваться как признак EOF. В офтопике, такой обработкой действительно занимается стандартная библиотека, но как именно вроде определяется только исторически сложившимися правилами. А в онтопике ctrl-d практически наверняка не доходит до приложения, так как его (если правильно помню) можно заменить другой комбинацией перенастроив терминал.

Не уверен, что с этим можно что-то сделать. Может стоит вводить из файла, а не с терминала, либо не полагаться на такой признак конца.

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

а не с терминала

задача предполагает именно ввод с терминалом

либо не полагаться на такой признак конца

в том-то и дело, что используемый признак конца — энд оф лайн,а вовсе не еоф, можно было бы заюзать любой другой, но проблемы это не решит — юзер всё равно может нажать ctrl + z

кстати, вот прямо сейчас попросил друга проверить на шарпе+вин7 — всё работает идеально (до этого тестил не на своём компе на икспишке+плюсы)

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

Контрол+чо-то это исключительно область терминала, и классически терминал закрывает дескриптор, а прога получает -1 при очередном read. В винде и досе был такой костыль, что символ, за который отвечает ctrl-z, доходил до библиотеки и она как бы понимала, что все, конец. Но дальше все равно можно было читать, хотя это уже особенность конкретного стдлиба.

Если хочешь знать, что действительно происходит, и где это происходит, читай read'ом и смотри, что залетело. Вполне возможно, что ввод-вывод в твоей библиотеке реализован по костыльной виндовой схеме.

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

В винде и досе был такой костыль, что символ, за который отвечает ctrl-z, доходил до библиотеки и она как бы понимала, что все, конец.

оно и в линуксе так. вот только в линкуксе ноу праблемс.

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

Да вроде не так. В юниксах все нажатия ловятся терминалом (например xterm ловит XEvent-ы) и перенаправляются твоей проге в stdin. Все, кроме определенных управляющих, среди них и ctrl-d. По нему терминал физически закрывает ответную часть stdin-дескриптора foreground процесса. Не прога ловит ввод, а терминал. Через иксы или консольный ядреный драйвер.

А вот в винде и досе остался пережиток cp/m, в которой размер файла был всегда кратен размеру сектора, поэтому файл насильно заканчивали символом ctrl-z, нетрудно догадаться, что это 26 десятичное. И при чтении откусывали все после него включительно, ибо мусор. Этот костыль переехал сначала в дос, а потом и в cmd.

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

И при чтении откусывали все после него включительно, ибо мусор.

было бы и здорово, если б оно откусывало. или хотя бы игнорировалось, так ведь нет.

я ввожу abc ctrl+z edf enter iklmn

результат: в строке — abciklmn, причём после энтера ввод не завершается, сам факт того, что меня зачем-то перекидывает на другую строчку вместо завершения ввода строки. причём на шарпе такая проблема не проявляется, значит — это не терминал виноват

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

Затруднительно либастралить, но может у проверяющего товарища виесто cmd какой-нибудь powershell? Можно хр-вендузятников попросить проверить copy con test.txt с твоими кнопками, возможно это просто нормальное поведение cmd. Ctrl-z enter же правильно работает, «проблема» только когда не-enter дальше пишешь?

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

в цмд

«проблема» только когда не-enter дальше пишешь?

вроде да.

copy con test.txt

что оно делает? я в виндовых утилках не силён

next_time ★★★★★
() автор топика

Пользуйся гуглом, прежде чем создавать темы. На stackoverflow обсосали этот вопрос не раз. Некоторые сведения: понятия EOF в виндовой консоли не существует. Консоль — не файл, кончиться не может. Обработка ^Z на совести приложения. Т.е. его libc, ^Z подаётся на вход при чтении, а как EOF его может вернуть функция вроде getchar. ^Z трактуется как EOF, когда с него начинается новая строка. ^Z в другом месте не EOF.

Вот как-то так

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

Я, похоже, неправильно понял что ты написал. Но у меня в Linux для зактрытия ввода с терминала при наличии введенные символов в текущей строке Ctrl+D надо нажать два раза подряд. Однократное нажатие, судя по всему, приводит к передачи введенной строки в приложение.

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

это правильное поведение терминала

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

пользовался. видимо, неправильно задавал гуглу вопрос.

Обработка ^Z на совести приложения. Т.е. его libc, ^Z подаётся на вход при чтении, а как EOF его может вернуть функция вроде getchar. ^Z трактуется как EOF, когда с него начинается новая строка. ^Z в другом месте не EOF.

ну да, баг в mingw, как я и думал. как бороться-то?

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

У него и у меня, если я его правильно понял, разное описание поведения терминала. А ты обоим говоришь, что так и надо. Ты уж определись. И, кстати, поведение терминала у меня соответствует тому, что ты описал в начале.

Я так понимаю, что у меня терминал работает приблизительно так: ^D приводит к сбросу буфера вводимых символов, а если буфер пуст, то к передаче EOF (т.е. очередной read вернёт 0)

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

^Z трактуется как EOF, когда с него начинается новая строка. ^Z в другом месте не EOF.

ну да, баг в mingw, как я и думал. как бороться-то?

Так в винде же вроде бы всегда так было?

theNamelessOne ★★★★★
()

Попробуй сначала нажать Ctrl-Z, а потом Enter. Это не баг MinGW - это причуды виндового терминала.

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

Я знак вопроса в конце не дописал. Насколько я помню, если есть введённые символы, то ^D после них не приводит к завершению ввода. По крайней мере в баше так.

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

Попробуй сначала нажать Ctrl-Z, а потом Enter. Это не баг MinGW - это причуды виндового терминала.

в программе на руби и той же ОС баг не проявляется

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

А ты обоим говоришь, что так и надо

может быть несколько правильных решений одного уравнения

основная ошибка в том, что после letters1 ^Z letters2 \n ввод заново повторяется

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

Консольный ввод-вывод в винде зделан хреновенько.

в программе на руби и той же ОС баг не проявляется

Не факт, что ruby использует для ввода вывода стандартную библиотеку - там вполне может частично свой run-time. А поведение mingw такое же, как и у стандртной библиотеки MSVC - там тоже так. Так что это не баг, а фича. Или правильнее воспроизведение заранее известного поведения, даже если оно и не кажется корректным. Кстати, некоторые сборки mingw линкуют экзешники сразу с мелкософтовым рантаймом (msvcrt.dll) (я юзаю TDM-GCC), так что это может быть и не копирование поведения другого рантайма.

arbv
()

mingw вообще очень странный компилятор. Я тоже так обламался разок. Довольно сложную и ресурсожрущую софтину накатал на чистом си под gcc. Потом пришлось в описании писать что собирать нужно только gcc.

Проблему, кстати, так и не нашел. После суток копания надоело.

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

Так что это не баг, а фича

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

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

кстати, фичу от бага очень легко отличить: фича должна быть отключаемой. в библиотеке это возможно сделать, например, через #ifdef

если фича не отключаема и приводит к странному, нелогичному поведению, это не фича, а баг

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

Хочешь - считай это фичей, хочешь - багом. От этого объективная реальность не изменится - рантайм как работал, так и будет работать. Даже если и не совсем логично.

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

рантайм как работал, так и будет работать.

нет. в руби, например, такой ошибки нет. возможно, существуют какие-то другие либы для плюсов, в которых этого бага нет.

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

Можешь попробовать обойти это поведение через WinAPI..Например, попробовав обработать Ctrl-Z вручную. Это геморно, я знаю.

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

Будучи компилятором для винды он учитывает её причуды. Насчёт других библиотек не знаю. Что смог подсказать уже подсказал.

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

ок. и на том спасибо.

Будучи компилятором для винды он учитывает её причуды

мог бы отключать такое поведение опционально

next_time ★★★★★
() автор топика

Используй системное API, а не говно, т.е. не стандартную библиотеку C++.

Бага никакого нет, это поведение терминала, т.е. консоли.

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