Я пытаюсь реализовать документ здесь, подобный тому, который используется в bash (в C), но я заметил, что не могу дать ему строку длиной более 4096 байт, я посмотрел ее, и это было из-за максимального размера. очередей ввода-вывода ядра, поэтому мой процесс никогда не получает полный ввод, который я набираю в оболочке. Между тем, heredoc bash справится с этим. Есть ли способ обойти это, используя C.
с любым словом, длина которого превышает 4096 символов, печатается только 4096 символов или входные данные повреждаются.
#include <unistd.h>
int main()
{
ssize_t r_bytes;
char buf[42];
while (r_bytes = read(0, buf, 42))
{
write(1, buf, r_bytes);
}
return (0);
}
1-Скомпилируйте и выполните этот код. 2-Введите это:
<start>herrslcrwhjsyxlnuvxoofkmnnqnqplyyomfekjdvifzmzqsjjffjlqgvxrmhplzfaywnsptodrwygvhtplduhivfefqefkwcrficiatatbvlpzikietxdfekfnqvgazseylfagktlaseeedbbeajmnvshwkzvlfyhdoswwzzdesnaphprclhihfdckjcpepytllszcucuyvgqlfreyknejkjbthgociqxzellhzgdqkpnglnaocygxqifkjikcrepkcosxclwqlhhgzndoqroocniwrjaoumuvlvtvdrsyaupmkldzhvurnzgwhpvsyzrqzxgtlythlqflciocyepzbxyepegfxifkuopqrivsnhzqhmjmbrdkoxwrgpmdntoqlksjxwrfdadkjzjvyknulhlhmseykfpqnpvfpfbxncefcbfzdfndkwskdusuhylklqcxnmbibgmerllmzgmorqpqawbiexnbgkuaxbiucrkfsxndhdifgrfiuyanximidvvfaqnurmsnvfnwahuvpyjjvpukbrkemqotmvnvqcwivueqisxqvrfunmaaeuguqpullxgyuypepxgkrmgpfxlihmazubjmnlifqoyfidhpvvpyraddjlxoalrhsrpviqkhmcszkluelumfpukwynrmlhdvnwhhukorlpqzouzakphkgorumfqabjxrtghrvynqazsoahewbhpujofcokzeapdlpkgzrrdnmmwintaoowbzctqnxatvfecwnirxaacqmsrbecdgikauqosygzyxkyfikryohidyslrizbwnnhbiwnqbbgqylhvkmtnazfdzvweucoqdovuzfuqlywxdfkmzgsssnprekjfnutlmhbdvtcngeitphqywvtmppptaxyielehppdxjgzuvwybjealhkjjlgibgjcysgvmgfvgqpnpmadtjlngmsxgvolvdlzkfyfqoujjiegunytjkxornyruaxgpqqjhqyfwymvyglnccfbdslqdbrqpmwtonklsajnuaemvkqwjuscectjwbvohfvuecltlkhszplqxipaymbtxjztjofubjblqrrantnfcsoirrvkwnvmwnwqpdsysqsokmwylnvvryhnaatnlbmvtfhbquzmnrukbvqbvwjdqrdgthrqpnjebcokbroruogaswulugwxkrrmbrkskqhlgbufanzafdsbgcqcjxntmczmzrsjqjfcpmetvjirmcpmfmobfslagzlvoppuachoyxbrgqejrdbykeczesigwwcmjdmvvzudouderjbhpihwaxhizaxejmckwnwgmhcgylephrukykldufcobjqrmiiqnxznmlnzpdbxgyxfnwdtgjeupvxdnzyvivpuvrfulypwzfgxmnomohfcvcyuhimpeelkwaurwcgcthvsfpppurrercewdfhryyyytzowizhtlzohewpqxjmacpgkhvjzopuoggswmowcbfhkdpkvbjajqjmqfqbovgiaojsfyaqzqmngemgytcsvsqfdpbcehxrcleqmguhnuipoqecwralfehnxrevtmgqbiqpfighujwpgqqfcumppeamwasfqkeochbptmezrmttngijtwawvojpmpkzozkkxzuxzggvcswowkjmtvtmzwptwolaflkddwbkmzxvnclqzsikajmyihcatjrnvqixbfnmpvigmmwmepppebohsidrquffvkmjxtuchozqbdcowfqpnrhxzrkxozpqfojuybxwcerlfmaveslyfnkvkphotyrdukcelzszlqaqyayvuzljfsgrltqherbwabxslbwxlrfnundvzvchgpllcenakkwaejdejpfqiarsomxgcoplpdrqdudcaopdxjziyvuqeolkqqopwzixmhpyaabjuoplqourpuzphjfyvvwoxlssgkkqrwewzikvkdgfwgtzkennzhlnuakywfiiwqvpsfqgkowunzfblrxiwqibulojvrjnbhgjookrazjzrhmhqxnxjmaupdczcwlhmhvaepgvdksckettpzqhkfbmszbqbqidnjnwcrloqduucjdgvisrlixrwsqtdrackbbwbfslpgrkycycqnbccebvcuivfkyejwwcfpuaqmuacfrcbjtmvwvcryuzlbvuwagcggiwwzxxbicvnwbafuubeqjuvrdcizwbnagdntjypfolexpesovyrupoxlnhtdcnhyppxoniqdpsfyhlarshtdgwbtbkjtklvdpztdumykphalytjaefwfhwhhnpqcwfcruhmmxoqngnvtfbxwfmfdkhivhitsdecqehowjmgxmdipdtsiwuxivdjmmwrkotqrdhwtnzfbhemboqkqkodaabxkedzkpxriuurifgfjhrtxpqlaoolqgbkdqyaatgnsdzhawpfhvwgtqjsdeopuwvgolouofwwzbhpeybvpglwwqjcjlqpsobgojoijblingffcrsydqcjjzlwoeklhxzecitrtihakcktvfnfblmhejybnsihzhmcgxayxoruyvnecnbbfpwieoejtfzjhjczduuldcflvwzjzruxlckvpyivtnyzfzdhfzptwjjggaeqsbgkkynqjpsuobflnaqbwayslrsvrgrbtjzhkbtmvicoxbdfexnuwzbvamumswnloymrjojujwtmcudbhcxvbxbcwzrzhjlrgoerptgczhldyskvqpqxxpuywrtltwyzkbpdmzgcaulbdygqfeoflgwnhtuaelesgjaawskmsccgyoqraabxppuueyfbdvuhvotgbswrtyfxliwkewxzpoetubihymgbmqnmaseemmonsgkbfsomawfjgxqqrjbfxpyissubkeafseucdpwasafhkkhsdygbgeypjesxeyafbdctkgorlcknmjtnqpjbkwwyztqailtefgjmkgujpynkfmtqnjvdqjgttnvejsvzahddzedysitrwumidnufktcozdfgshwzicuykokdjxszhcsimalzijyvylkaxdweafmtfgtkaepteyafqijbonhgxrqnkxwtpceajseopimpkvouzajzrrtbpiymsqxnrkmpejokpancnmmcincaddywnozsknikimutldarwabrzgvymatbamsbwaikbwatvqbpvfsdeafycximswbehmyzwzarqvcjtzyofhfjxagtrehvssqsbtowueuizqjuyjrulldgxtjtkirekhwaxhdfcnbwhyqtuinxpxddkvoiveoenwsgixpqqxupuunrgyddowemsegsovkigdwxgefzvmiuuafynnxukixpsnmiwszojlmcxvopwdazpcuxetclgatgzmvmeecppggaqhobatlyynzhdygxiatrktpgntmkqcjkuxmdlroounnxcebepchuokotvmqfctmtjsnplgjmeobzbwhxekvlbknvwughuppzuecumvqjylqkhlmpbbhmgrenotwyyquqhgrrboqvjskaczyhnukqogmqbngkrvsakcppveykzuqmsbxdfxjulofmpnilynqzzgdxbdjjzhskrthbwzjzugjsutgpgkromaccbjqitrhxlahzaygcvztjycifokrbxugvdmwxqqxibhgckxwhabbjsmnpencsplrxjnfanqtdgrruiomesapwfdvsotvkgqgfxeelavujnigyedrhwksraopenosfgbrdvogtudmxecvrvxvjjuaodjvajlgazeqsyemyysxpnilklpvzciwidtjebaczuhezsresvglzivbbodxakeighfawfanvdzzpadrcisfsqyhfbuyurppqdfekrolbzxvquulxhnwwndndirrcysbywooygizgbuiezholvuoqkyiorttcmzpseippnxkuilfsrxfknzkvzlqmdlupqkxdjxtiuxjghikocnpkocoauecaofnsyouizpbgvytkpxrfalhvpqymbxqetmozufwmcbycsalporhqzlfpbeqgffteuqeatujlrjyjhjjjhj<end>helloworld
и на выходе будет все до <конца> или строки из 4096 символов, которая будет повреждена.
Согласно справочной странице функции read: В Linux read() (и подобные системные вызовы) передадут не более 0x7ffff000 (2 147 479 552) байт, возвращая количество фактически переданных байтов. (Это справедливо как для 32-битных, так и для 64-битных систем.). Вам необходимо предоставить более подробную информацию о ваших тестах, когда вы пытаетесь прочитать 4096 байт.
При использовании read вы, скорее всего, захотите проверить, читаете ли вы символы > 0. Обратите внимание, что он может вернуть -1, и в этом случае вы попытаетесь writesize_t(-1) байт, что очень много, и получите доступ к вашему buf за пределами границ.
@EricPostpischil Я знаю, что код в целом правильный, но в случае, скажем, текста из 5000 символов вы заметите, что он будет читать только 4096 символов, независимо от того, какой входной сигнал или размер буфера. извините за путаницу.
@AnassAbidar: Я не замечаю такого поведения. Перестаньте описывать якобы нерабочий код и вместо этого предоставьте его точную копию. Отредактируйте вопрос, чтобы предоставить минимально воспроизводимый пример. Также предоставьте полное описание предоставленных вами входных данных и наблюдаемых результатов, чтобы другой человек мог точно воспроизвести проблему.
Я подозреваю, что ваша реальная проблема не в «максимальном размере очередей ввода-вывода ядра», а в том, что ваше терминальное программное обеспечение не принимает строки длиной более 4096 символов.
Перенаправьте вывод в файл и сравните этот новый файл с исходным файлом.
@EricPostpischil нет, это действительно из-за емкости буфера псевдотерминала, независимой от фактического программного обеспечения терминала.
@Ctx: Емкость буфера псевдотерминала является частью программного обеспечения терминала. По-прежнему нет ограничения на «максимальный размер очередей ввода-вывода ядра».
@EricPostpischil Если драйвер pty для Linux является частью программного обеспечения терминала, то да.
@Ctx: Конечно, это так. Это программное обеспечение, а не аппаратное обеспечение, и оно обеспечивает работу интерфейса терминала.
@EricPostpischil Хорошо, тогда я неправильно понял ваше утверждение, я не думал, что вы пойдете здесь на банальности.
@Ctx: Откуда ты знаешь, что это псевдотерминал? Если терминальное приложение создает псевдотерминал, принимает множество нажатий клавиш с клавиатуры и записывает, скажем, 10 000 байт в псевдотерминал для чтения подключенным потоком, почему бы псевдотерминалу не принимать байты до тех пор, пока его буфер не заполнится (оставив писатель заблокирован), сделать их доступными для чтения, а когда программа ОП их прочитает, возобновить операцию записи терминального приложения? Мне кажется более вероятным, что это выбранное ограничение пользовательского интерфейса в терминальном приложении, чем ограничение нижнего уровня.
@AnassAbidar Вы пытались перенаправить вывод вашей программы в файл, а затем сравнить этот новый файл с исходным файлом?
@EricPostpischil Прочтите раздел о каноническом режиме в termios(3).
@TedLyngmo предоставленный мною фрагмент кода представляет собой упрощенную версию того, что я пытаюсь сделать (реализовать документ bash here с помощью c). Мне нужно прочитать вводимые пользователем данные со стандартного ввода, как это делает обычный документ здесь.
@AnassAbidar Кстати, я думаю, что ваш вопрос совершенно справедлив, и вы предоставили хороший MCVE. Следовательно, закрытие вопроса по указанной выше причине, на мой взгляд, неоправданно. Тем не менее, вы получили хороший ответ ниже, я не думаю, что вы можете сделать здесь что-то большее. Если вы не можете переключить режим терминала, вам не повезло, если только я здесь что-то не упустил.
@Ctx ну, это то, что есть, спасибо за помощь. спасибо всем за обсуждение, многому научился
@AnassAbidar Ты не ответил на мой вопрос. Если вы перенаправите вывод в файл и получите точно такой же контент, как и в исходном файле, ваша программа, скорее всего, поступает правильно (за исключением того, что вы не имеете дело с -1). Пробовали ли вы вместо этого использовать стандартные функции C fread/fwrite?
@Ctx: Голосование за закрытие началось до того, как OP обновился с помощью образца входных данных. Учитывая его нынешнее состояние, я, возможно, не проголосовал бы за его закрытие, но, учитывая, что он закрыт, я не буду голосовать за его повторное открытие, пока он не будет улучшен. Там написано «Я посмотрел», но не указано, где и что именно было найдено. Там написано, что «это произошло из-за максимального размера очередей ввода-вывода ядра», но это сомнительно. Там написано «любое слово, превышающее…», но на самом деле проблема заключается в строке, а не в слове. Там говорится, что «входные данные повреждены», но это сомнительно и должно сопровождаться доказательствами.
@EricPostpischil Неважно, как я уже сказал, ответ ниже хорош и затрагивает суть проблемы. Склонны согласиться сейчас?





Чтобы обрабатывать строки ввода длиной более 4096 байт в C, вы можете переключить терминал в неканонический режим (также известный как режим Raw).
В неканоническом режиме ввод доступен сразу, без ожидания перехода на новую строку, что позволяет обрабатывать ввод, размер которого превышает типичный размер буфера.
Посмотрите на свой код, измененный, как описано выше:
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
void setRawMode(int fd) {
struct termios term;
tcgetattr(fd, &term);
term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(fd, TCSANOW, &term);
}
void setCanonicalMode(int fd) {
struct termios term;
tcgetattr(fd, &term);
term.c_lflag |= (ICANON | ECHO);
tcsetattr(fd, TCSANOW, &term);
}
int main() {
setRawMode(STDIN_FILENO);
ssize_t r_bytes;
char buf[64];
while ((r_bytes = read(STDIN_FILENO, buf, sizeof(buf) - 1)) > 0) {
buf[r_bytes] = '\0';
printf("%s", buf);
}
setCanonicalMode(STDIN_FILENO);
return 0;
}
Спасибо за ответ! но, к сожалению, я могу использовать только эти функции c: open, close, read, write, malloc, free, perror, strerror, access, dup, dup2, execve, exit, fork, pipe, unlink, wait, waitpid, есть идеи, если это все еще в моем случае поправимо
Возможно, это ограничение оболочки. Но в любом случае, вы вводите в терминал 4097 символов? Вы передаете файл в свой исполняемый файл? Пожалуйста, отредактируйте и расскажите нам больше. Что именно ты делаешь?