Разница между% ms и% s scanf

Вопрос:Чтение руководства scanf Я встречаю эту строку: Необязательный символ "m". Это используется для преобразования строк (% s,% c,% [), Может ли кто-нибудь объяснить это простым примером, указав разницу и необходимость такой опции в некоторых случаях? Лучший ответ: Стандарт C не определяет такой необязательный символ в форматах scanf(). GNU lib C, таким образом определяет необязательный индикатор

Вопрос:

Чтение руководства scanf Я встречаю эту строку:

Необязательный символ “m”. Это используется для преобразования строк               (% s,% c,% [),

Может ли кто-нибудь объяснить это простым примером, указав разницу и необходимость такой опции в некоторых случаях?

Лучший ответ:

Стандарт C не определяет такой необязательный символ в форматах scanf().

GNU lib C, таким образом определяет необязательный индикатор a (с man-страницы для scanf):

Необязательный символ a. Это используется со строковыми преобразованиями и освобождает вызывающего абонента от необходимости назначать соответствующий буфер для хранения ввода: вместо этого scanf() выделяет буфер достаточного размера и присваивает адрес этого буфера соответствующему аргументу указателя, который должен быть указателем на переменную char * (эта переменная не должна быть инициализирована перед вызовом).

Затем вызывающий абонент должен free использовать этот буфер, когда он больше не требуется. Это расширение GNU; C99 использует символ a как спецификатор преобразования (и его также можно использовать как таковой в реализации GNU).

В разделе ПРИМЕЧАНИЯ на странице руководства говорится:

Модификатор a недоступен, если программа скомпилирована с помощью gcc -std=c99 или gcc -D_ISOC99_SOURCE (если не указано _GNU_SOURCE), и в этом случае a интерпретируется как спецификатор для плавающей запятой числа (см. выше).

Начиная с версии 2.7, glibc также предоставляет модификатор m для той же цели, что и модификатор. Модификатор m имеет следующие преимущества:

  • Он также может применяться к %c спецификаторам преобразования (например, %3mc).

  • Он избегает двусмысленности относительно спецификатора преобразования %a с плавающей запятой (и на него не влияет gcc -std=c99 и т.д.)

  • Он указан в предстоящей ревизии стандарта POSIX.1.

Страница руководства онлайн-linux на документирует этот параметр как:

Необязательный символ “m”. Это используется с строковыми преобразованиями (%s, %c, %[), и снимает вызывающий абонент о необходимости выделения соответствующего буфера для хранения ввода: вместо этого, scanf() выделяет буфер достаточного размера, и присваивает адрес этого буфера соответствующему аргументу указателя, который должен быть указателем на переменную char * (эта переменная не должна быть инициализирована перед вызовом). Затем вызывающему абоненту следует free(3) этот буфер, когда он больше не требуется.

Стандарт Posix документирует это расширение в своем выпуске POSIX.1-2008 (см. http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html):

Спецификаторы преобразования %c, %s и %[ должны принимать необязательный символ назначения назначения m, который должен вызывать буфер памяти для хранения преобразованной строки, включая завершающий нулевой символ. В этом случае аргумент, соответствующий спецификатору преобразования, должен быть ссылкой на переменную-указатель, которая получит указатель на выделенный буфер. Система должна выделять буфер, как если бы был вызван malloc(). Приложение должно отвечать за освобождение памяти после использования. Если для выделения буфера недостаточно памяти, функция должна установить errno в [ENOMEM], и в результате будет получена ошибка преобразования. Если функция возвращает EOF, любая память, успешно назначенная для параметров с использованием символа выделения назначения m этим вызовом, должна быть освобождена до возвращения функции.

Используя это расширение, вы можете написать:

char *p; scanf(«%ms», &p);

Вызов scanf для разбора слова со стандартного ввода и выделения достаточного количества памяти для хранения его символов плюс завершающий ‘’. Указатель на выделенный массив будет храниться в p, а scanf() будет возвращать 1, если не будут пропущены никакие пробельные символы из stdin.

Вполне возможно, что другие системы используют m для аналогичной семантики или для чего-то еще целиком. Нестандартные расширения не являются переносимыми и должны использоваться очень тщательно, задокументированы как таковые, в условиях, когда стандартный подход громоздки непрактичен или вообще невозможен.

Обратите внимание, что разбор слова произвольного размера действительно невозможно при стандартной версии scanf():

Вы можете проанализировать слово с максимальным размером и указать максимальное количество символов для хранения перед ‘’:

char buffer[20]; scanf(«%19s», buffer);

Но это не говорит вам, сколько еще символов доступно для синтаксического анализа в стандартном вводе. В любом случае, не пропуская максимальное количество символов, вы можете вызвать поведение undefined, если вход достаточно длинный, и специально созданный ввод может даже использоваться злоумышленником для компрометации вашей программы:

char buffer[20]; scanf(«%s», buffer); // potential undefined behavior, // that could be exploited by an attacker.

Оцените статью
Добавить комментарий