Что означает "_"? Почему Microsoft добавляет этот знак в начале?
Почему в msvС++ у нас есть _snprintf, тогда как другие компиляторы позволяют snprintf
Ответ 1
Идентификаторы в глобальном пространстве имен, начиная с _
, зарезервированы для реализации. _snprintf
- это просто функция, предоставленная реализацией (Visual Studio). Что касается обоснования этого, Visual Studio реализует C89, а snprintf
является частью более позднего стандарта C99.
Кроме того, семантика обеих функций различна в обратном типе, который в snprintf
всегда является числом символов, которые принимает форматированная строка (было ли достаточно свободного места в буфере или нет, а _snprintf
будет возвращать отрицательное число, если в буфере недостаточно места.
То есть, чтобы выделить буфер, достаточно большой для вывода, который вы можете сделать:
int size = snprintf( 0, 0, "%s %d\n", str, i );
char * buffer = malloc( size+1 );
snprintf( buffer, size+1, "%s %d\n", str, i );
Вы не можете сделать это с помощью _snprintf
, поскольку единственная информация, возвращаемая функцией, заключается в том, что текущего размера недостаточно.
Ответ 2
snprintf()
еще не был частью стандарта на тот момент, когда среда выполнения Microsoft C начала поддерживать его.
Поскольку прототип функции не был стандартизован, и разработчики не хотели использовать имя snprintf
(в случае, если стандарт позже указывал другой прототип), они решили добавить главное подчеркивание, чтобы обозначить функцию как Расширение Microsoft для стандарта.
Ответ 3
Добавление к приведенному выше,
существуют соответствующие C99 snprintf()
и vsnprintf()
, доступный с Visual Studio 2015
и они даже не запускают известное предупреждение о небрежном предупреждении функции. _snprintf_s()
или _vsnprintf_s()
, при условии, являются "безопасными вариантами" функций, специфичных для MSVC, с поведением, отличным от C99.
Ответ 4
Помимо другого возвращаемого значения в случае недостаточно большого буфера (описанного в ответе Дэвида), функции из группы _sn...
отличаются от стандартного snprintf
в другом важном отношении. Если целевой буфер слишком короткий одним символом, функции _sn...
считают эту ситуацию "успешной".
Более подробно, если целевой буфер достаточно длинный, чтобы сохранить всю результирующую последовательность, но без конечного нулевого символа, функции _sn...
не обрезают результат, не записывают нулевой нуль в целевой буфер и возвращают размер буфера в результате. Таким образом, в общем случае результат не гарантируется с нулевым завершением.
В той же ситуации snprintf
будет отбрасывать последний символ результирующей последовательности и записывать нулевой терминатор на свое место. Результат snprintf
всегда заканчивается нулем.