Является ли поддержка регулярных выражений scanf стандартом?

#c #gcc #scanf

#c #gcc #scanf

Вопрос:

Является ли поддержка регулярных выражений scanf стандартом? Я нигде не могу найти ответ.

Этот код работает в gcc, но не в Visual Studio:

 scanf("%[^n]",a);
  

Это ошибка Visual Studio или расширение gcc?

РЕДАКТИРОВАТЬ: Похоже, что VS работает, но нужно учитывать разницу в концах строк между Linux и Windows.( r n)

Комментарии:

1. Спасибо, что указали на функцию, о существовании которой я никогда не подозревал; однако обратите внимание, что scanf(3) и friends являются библиотечными функциями и предоставляются не gcc , а скорее библиотекой C (обычно glibc в системах Linux, но доступно несколько библиотек C).

2. Что вы имеете в виду, scanf("%[^n]",a); не работает в Visual Studio? У меня это работает. Опубликуйте больше кода (конкретно, что такое a ), ввода, вывода и ожидаемого результата.

3. Майкл, уверен, что код компилируется. Но он ведет себя не так, как версия Linux. Мой код продолжает прыгать с r n в буфере. Я изменю фильтр на r n, чтобы проверить позже. Спасибо!

4. Это отличный вопрос для проверки глубоких знаний библиотеки C.

5. Проблема, похоже, в том, что вы читаете текстовый файл в двоичном режиме . В C в строках должны быть только n как терминаторы строки.

Ответ №1:

Эта конкретная строка формата должна нормально работать в соответствующей реализации. [ Символ вводит набор сканирования для сопоставления с непустым набором символов (что ^ означает, что набор сканирования является инверсией предоставленных символов). Другими словами, спецификатор формата %[^n] должен соответствовать каждому символу, который не является новой строкой.

Из C99 7.19.6.2, слегка перефразировано:

[ Спецификатор формата сопоставляет непустую последовательность символов из набора ожидаемых символов (scanset). Если нет l длина присутствует модификатор, соответствующий аргумент должен быть указателем на начальный элемент массива символов, достаточно большой, чтобы принять последовательность и завершающий нулевой символ, которые будут добавлены автоматически.

Если присутствует l модификатор длины, вводом должна быть последовательность многобайтовых символов, которая начинается с начального состояния сдвига. Каждый многобайтовый символ преобразуется в широкий символ, как будто с помощью вызова mbrtowc функции, при этом состояние преобразования описывается mbstate_t объектом, инициализированным нулем перед преобразованием первого многобайтового символа. Соответствующий аргумент должен быть указателем на начальный элемент массива wchar_t , достаточно большого, чтобы принять последовательность и завершающий символ null wide, который будет добавлен автоматически.

Спецификатор преобразования включает все последующие символы в строке формата, вплоть до соответствующей правой скобки включительно ] . Символы между скобками (список сканирования) составляют набор сканирования, если только символ после левой скобки не является окружностью ^ , в этом случае набор сканирования содержит все символы, которые не отображаются в списке сканирования между окружностью и правой скобкой. Если спецификатор преобразования начинается с [] или [^] , символ правой скобки находится в списке сканирования, а следующий за правой скобкой символ — это соответствующая правая скобка, которая завершает спецификацию; в противном случае первым следующим символом правой скобки является тот, который завершает спецификацию. Если - символ находится в списке сканирования и не является ни первым, ни вторым, где первым символом является ^ , ни последним символом, поведение определяется реализацией.

Возможно, если MSVC работает некорректно, это всего лишь один из многих примеров, когда Microsoft либо не соответствует последнему стандарту, либо думает, что они знают лучше 🙂

Комментарии:

1. Я полагаю, что несоответствующая часть может быть способом a получения ее содержимого. Если вы открываете текстовый файл в двоичном режиме и пытаетесь обработать строки, вам придется переводить окончания строк самостоятельно.

2. Поддержка наборов сканирования "%[...]" появилась scanf() в 7-м издании UNIX ™ в 1979 году. Он по крайней мере на десять лет старше любого стандарта C.

Ответ №2:

"%[" Спецификация формата для scanf() является стандартной и действует с C90.

MSVC действительно поддерживает это.

Вы также можете указать ширину поля в спецификации формата, чтобы обеспечить защиту от переполнения буфера:

 int main()
{
    char buf[9];

    scanf("%8[^n]",buf);

    printf("%sn", buf);
    printf("strlen(buf) == %un", strlen(buf));

    return 0;
}
  

Также обратите внимание, что "%[" спецификация формата не означает, что он scanf() поддерживает регулярные выражения. Эта конкретная спецификация формата похожа на возможности регулярных выражений (и, без сомнения, на нее повлияло regex), но она гораздо более ограничена, чем регулярные выражения.

Комментарии:

1. Примечание: scanf("%8[^n]",buf); ничего не считывает, если ввод "n" . buf остается неинициализированным.