C fgets против fgetc для чтения строки - PullRequest
11 голосов
/ 03 марта 2011

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

  • Используйте fgets и проверяйте каждый раз, является ли последний символ новой строкой, и постоянно добавляйте в буфер
  • Читайте каждый символ, используя fgetcи иногда realloc буфер

Интуиция говорит мне, что вариант fgetc может быть медленнее, но опять же я не понимаю, как fgets может сделать это без проверки каждого символа (также мойинтуиция не всегда так хороша).Линии довольно большие, поэтому производительность важна.

Я хотел бы знать плюсы и минусы каждого подхода.Заранее спасибо.

Ответы [ 5 ]

2 голосов
/ 04 марта 2011

Если производительность очень важна для вас, вы обычно хотите звонить getc вместо fgetc. Стандарт пытается упростить реализацию getc в качестве макроса, чтобы избежать накладных расходов при вызове функции.

Кроме того, главное, с чем нужно иметь дело, - это, вероятно, ваша стратегия в распределении буфера. Большинство людей используют фиксированные приращения (например, когда / если у нас заканчивается свободное место, выделите еще 128 байтов). Вместо этого я бы посоветовал использовать постоянный коэффициент , поэтому, если вам не хватает места, выделите буфер, скажем, в 1 1/2 раза от предыдущего размера.

Особенно, когда getc реализован в виде макроса, разница между getc и fgets обычно весьма минимальна, поэтому лучше сосредоточиться на других вопросах.

2 голосов
/ 04 марта 2011

Обеспечивает ли ваша среда функцию getline(3)?Если так, я бы сказал, пойти на это.

Большое преимущество, которое я вижу, состоит в том, что он выделяет сам буфер (если вы хотите) и realloc() буфер, который вы передаете, если он слишком мал.(Таким образом, это означает, что вам нужно передать что-то, полученное из malloc()).

Это избавит от некоторой боли fgets / fgetc, и вы можете надеяться, что тот, кто написал библиотеку C, реализующую это, взялпозаботьтесь о том, чтобы сделать его эффективным.

Бонус: на странице руководства по Linux есть хороший пример того, как эффективно его использовать.

2 голосов
/ 04 марта 2011

Я предлагаю использовать fgets() в сочетании с динамическим распределением памяти - или вы можете исследовать интерфейс к getline(), который соответствует стандарту POSIX 2008 и доступен на более поздних машинах Linux.Это делает выделение памяти для вас.Вам нужно следить за длиной буфера и его адресом - так что вы можете даже создать себе структуру для обработки информации.

Хотя fgetc() также работает, она немного более утомительна - но лишь незначительно, поэтому,Под крышками используются те же механизмы, что и fgets().Внутренние устройства могут использовать более быструю работу, аналогичную strchr(), которая недоступна при прямом вызове fgetc().

0 голосов
/ 04 марта 2011

Я бы выделил большой буфер, а затем использовал бы fgets, проверяя, восстанавливая и повторяя, если вы не читали до конца строки.

Каждый раз, когда вы читаете (либо через fgetc, либо через fgets), вы делаете системный вызов, который требует времени, вы хотите минимизировать количество раз, которое происходит, поэтому вызов fgets выполняется меньше раз, и итерация в памяти происходит быстрее.

Если вы читаете из файла, mmap() в файле - это еще один вариант.

0 голосов
/ 04 марта 2011

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

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

...