ungetc: количество байтов pushback
ungetc гарантированно принимает только один байт pushback. С другой стороны, я протестировал его на Windows и Linux, и он работает с двумя байтами.
Существуют ли какие-либо платформы (например, какие-либо текущие системы Unix), на которых он фактически занимает всего один байт?
3 ответа
Стандарт C99 (и стандарт C89 до этого) однозначно сказал:
Один символ отталкивания гарантирован. Если
ungetc
функция вызывается слишком много раз в одном и том же потоке без промежуточной операции чтения или позиционирования файла в этом потоке, операция может завершиться ошибкой.
Таким образом, чтобы быть переносимым, вы не предполагаете более одного символа откатывания назад.
При этом на MacOS X 10.7.2 (Lion) и RHEL 5 (Linux, x86/64) я попытался:
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 4096; i++)
{
int c = i % 16 + 64;
if (ungetc(c, stdin) != c)
{
fprintf(stderr, "Error at count = %d\n", i);
return(1);
}
}
printf("No error up to count = %d\n", i-1);
return(0);
}
Я не получил ошибки ни на одной платформе. Напротив, в Solaris 10 (SPARC) я получил сообщение об ошибке "count = 4". Хуже того, в HP-UX 11.00 (PA-RISC) и HP-UX 11.23 (Itanium) я получил ошибку при 'count = 1', опровергающую теорию о том, что 2 безопасно. Точно так же AIX 6.0 выдал ошибку при 'count = 1'.
Резюме
- Linux: большой (4 КиБ)
- MaxOS X: большой (4 КиБ)
- Солярис: 4
- HP-UX: 1
- AIX: 1
Таким образом, AIX и HP-UX допускают только один символ возврата во входной файл, для которого не было прочитано никаких данных. Это неприятный случай; они могут обеспечить гораздо большую емкость отката после считывания некоторых данных из файла (но простой тест на AIX, добавляющий getchar()
до того, как цикл не изменил емкость отжима).
Реализации, которые поддерживают 2 символа pushback, вероятно, делают это для того, чтобы scanf
можешь использовать ungetc
для его отдачи, а не требует второго почти идентичного механизма. Это означает, что для вас, как для программиста приложения, даже при вызове ungetc
дважды, кажется, работает, это может быть не надежно во всех ситуациях - например, если последняя операция в потоке была fscanf
и он должен был использовать pushback, вы можете только ungetc
один персонаж
В любом случае, нельзя полагаться на наличие более чем одного символа ungetc
Пушбэк, поэтому я настоятельно рекомендую не писать код, который нуждается в этом...
Здесь есть несколько постов, предполагающих, что имеет смысл поддерживать 2 символа ради scanf
,
Я не думаю, что это правильно scanf
нужен только один, и это действительно причина ограничения. Первоначальная реализация (еще в середине 70-х годов) поддерживала 100, и в руководстве было примечание: в будущем мы можем решить поддерживать только 1, так как это все, что нужно для scanf. См. Страницу 3 оригинального руководства (возможно, не оригинальное, но довольно старое.)
Чтобы более наглядно увидеть, что scanf требуется всего 1 символ, рассмотрим этот код для %u
особенность scanf
,
int c;
while isspace(c=getc()) {} // skip white space
unsigned num = 0;
while isdigit(c)
num = num*10 + c-'0',
c = getc();
ungetc(c);
Только один звонок ungetc()
нужен здесь. Там нет причин, почему scanf
нуждается в символе все для себя: он может поделиться с пользователем.