Чтение и запись более 4096 байт в/из STDIN

Я пытаюсь реализовать документ здесь, подобный тому, который используется в 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 символов, которая будет повреждена.

Возможно, это ограничение оболочки. Но в любом случае, вы вводите в терминал 4097 символов? Вы передаете файл в свой исполняемый файл? Пожалуйста, отредактируйте и расскажите нам больше. Что именно ты делаешь?

Jabberwocky 16.04.2024 15:06

Согласно справочной странице функции read: В Linux read() (и подобные системные вызовы) передадут не более 0x7ffff000 (2 147 479 552) байт, возвращая количество фактически переданных байтов. (Это справедливо как для 32-битных, так и для 64-битных систем.). Вам необходимо предоставить более подробную информацию о ваших тестах, когда вы пытаетесь прочитать 4096 байт.

OldBoy 16.04.2024 15:07

При использовании read вы, скорее всего, захотите проверить, читаете ли вы символы > 0. Обратите внимание, что он может вернуть -1, и в этом случае вы попытаетесь writesize_t(-1) байт, что очень много, и получите доступ к вашему buf за пределами границ.

Ted Lyngmo 16.04.2024 15:09

@EricPostpischil Я знаю, что код в целом правильный, но в случае, скажем, текста из 5000 символов вы заметите, что он будет читать только 4096 символов, независимо от того, какой входной сигнал или размер буфера. извините за путаницу.

Anass Abidar 16.04.2024 15:18

@AnassAbidar: Я не замечаю такого поведения. Перестаньте описывать якобы нерабочий код и вместо этого предоставьте его точную копию. Отредактируйте вопрос, чтобы предоставить минимально воспроизводимый пример. Также предоставьте полное описание предоставленных вами входных данных и наблюдаемых результатов, чтобы другой человек мог точно воспроизвести проблему.

Eric Postpischil 16.04.2024 15:21

Я подозреваю, что ваша реальная проблема не в «максимальном размере очередей ввода-вывода ядра», а в том, что ваше терминальное программное обеспечение не принимает строки длиной более 4096 символов.

Eric Postpischil 16.04.2024 15:25

Перенаправьте вывод в файл и сравните этот новый файл с исходным файлом.

Ted Lyngmo 16.04.2024 15:26

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

Ctx 16.04.2024 15:27

@Ctx: Емкость буфера псевдотерминала является частью программного обеспечения терминала. По-прежнему нет ограничения на «максимальный размер очередей ввода-вывода ядра».

Eric Postpischil 16.04.2024 15:29

@EricPostpischil Если драйвер pty для Linux является частью программного обеспечения терминала, то да.

Ctx 16.04.2024 15:30

@Ctx: Конечно, это так. Это программное обеспечение, а не аппаратное обеспечение, и оно обеспечивает работу интерфейса терминала.

Eric Postpischil 16.04.2024 15:31

@EricPostpischil Хорошо, тогда я неправильно понял ваше утверждение, я не думал, что вы пойдете здесь на банальности.

Ctx 16.04.2024 15:33

@Ctx: Откуда ты знаешь, что это псевдотерминал? Если терминальное приложение создает псевдотерминал, принимает множество нажатий клавиш с клавиатуры и записывает, скажем, 10 000 байт в псевдотерминал для чтения подключенным потоком, почему бы псевдотерминалу не принимать байты до тех пор, пока его буфер не заполнится (оставив писатель заблокирован), сделать их доступными для чтения, а когда программа ОП их прочитает, возобновить операцию записи терминального приложения? Мне кажется более вероятным, что это выбранное ограничение пользовательского интерфейса в терминальном приложении, чем ограничение нижнего уровня.

Eric Postpischil 16.04.2024 15:41

@AnassAbidar Вы пытались перенаправить вывод вашей программы в файл, а затем сравнить этот новый файл с исходным файлом?

Ted Lyngmo 16.04.2024 15:41

@EricPostpischil Прочтите раздел о каноническом режиме в termios(3).

Ctx 16.04.2024 15:52

@TedLyngmo предоставленный мною фрагмент кода представляет собой упрощенную версию того, что я пытаюсь сделать (реализовать документ bash here с помощью c). Мне нужно прочитать вводимые пользователем данные со стандартного ввода, как это делает обычный документ здесь.

Anass Abidar 16.04.2024 15:54

@AnassAbidar Кстати, я думаю, что ваш вопрос совершенно справедлив, и вы предоставили хороший MCVE. Следовательно, закрытие вопроса по указанной выше причине, на мой взгляд, неоправданно. Тем не менее, вы получили хороший ответ ниже, я не думаю, что вы можете сделать здесь что-то большее. Если вы не можете переключить режим терминала, вам не повезло, если только я здесь что-то не упустил.

Ctx 16.04.2024 16:02

@Ctx ну, это то, что есть, спасибо за помощь. спасибо всем за обсуждение, многому научился

Anass Abidar 16.04.2024 16:12

@AnassAbidar Ты не ответил на мой вопрос. Если вы перенаправите вывод в файл и получите точно такой же контент, как и в исходном файле, ваша программа, скорее всего, поступает правильно (за исключением того, что вы не имеете дело с -1). Пробовали ли вы вместо этого использовать стандартные функции C fread/fwrite?

Ted Lyngmo 16.04.2024 16:34

@Ctx: Голосование за закрытие началось до того, как OP обновился с помощью образца входных данных. Учитывая его нынешнее состояние, я, возможно, не проголосовал бы за его закрытие, но, учитывая, что он закрыт, я не буду голосовать за его повторное открытие, пока он не будет улучшен. Там написано «Я посмотрел», но не указано, где и что именно было найдено. Там написано, что «это произошло из-за максимального размера очередей ввода-вывода ядра», но это сомнительно. Там написано «любое слово, превышающее…», но на самом деле проблема заключается в строке, а не в слове. Там говорится, что «входные данные повреждены», но это сомнительно и должно сопровождаться доказательствами.

Eric Postpischil 16.04.2024 16:35

@EricPostpischil Неважно, как я уже сказал, ответ ниже хорош и затрагивает суть проблемы. Склонны согласиться сейчас?

Ctx 16.04.2024 16:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
21
205
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы обрабатывать строки ввода длиной более 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, есть идеи, если это все еще в моем случае поправимо

Anass Abidar 16.04.2024 15:26

Другие вопросы по теме