Программирование >>  Обобщенные обратные вызовы 

1 2 3 4 [ 5 ] 6 7 8 ... 84


пример 3-1: преобразование данных в строку с использованием функции snprintf.

void PrettyFormatC int i, char* Этот код столь же прост, более безопасен: snprintfС buf, buflen, %4d

buf, int buflen ) { как и ранее, но уже

i );

Заметим, что при этом все равно остается возможность для ошибки --- вызываю-щая функция может передать неверный размер буфера. Это означает, что 100% безопасности в плане переполнения буфера не обеспечивает и snprintf, но она гораздо безопаснее функции sprintf. На вопрос Безопасна ли эта функция в смысле переполнения буфера? следует однозначно ответить Да .

Заметим, что некоторые достандартные версии функции snpri ntf вели себя несколько иначе. В частности, в одной из распространенных реализаций при полном заполнении буфера он не завершался нулевым символом. В такой ситуации наша функция PrettyFormat должна немного отличаться от исходного варианта, чтобы учесть такое нестандартное поведение.

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

void PrettyFormatC int i, char* buf, i nt buflen ) { Этот код столь же прост, как и ранее, но уже более безопасен:

ifС buflen > О ) {

snprintfC buf, buflen-l, buf[buflen-l] = \0;

%4d , i );

Bo всех остальных отношениях функции sprintf и snpri ntf идентичны. Приведем следующую таблицу сравнения snpri ntf и spri ntf.

snprintf

sprintf

Стандартность?

Да: только в 1С99], но, вероятно, будет и в

С++Ох

Простота использования и

ясность?

Эффективность, без излишних

распределений памяти?

Безопасность в плане

переполнения буфера?

Безопасность типов?

Использование в шаблонах?

Да: [С90], 1С++031, [С99]

Из этого сравнения вполне логично вытекает следующая рекомендация.

> Рекомендация

Никогда не используйте функцию spri ntf.

Если вы решите использовать возможности стандартного ввода-вывода из С, всегда используйте только тс функции, которые проверяют размер буфера, такие как



snprintf, даже если эти функции в вашем компиляторе доступны только в качестве нестандартного расширения. При использовании snpri ntf вместо sprintf нет никаких неприятностей, зато есть очень важное преимушество.

Когда я представлял этот материал на нескольких конференциях, я был шокирован тем, что только примерно каждый десятый знал о сушсствовании такой функции, как snpri ntf. Зато на каждой конференции кто-нибудь рассказывал, как в его проекте были обнаружены несколько случаев переполнения буфера, после чего sprintf были повсеместно заменены на snpri ntf. В результате тестирования оказывалось, что кроме явных ошибок, связанных с переполнением буфера и известных программистам, чудесным образом пропадали и ошибки, на которые им указывали годами, но которые они никак не могли локализовать.

Итак, еще раз: забудьте о существовании функции sprintf.

Альтернатива №2: std;:stringstream б) std::stringstream

Наиболее распространенным средством для строкового представления данных в С++ является семейство stri ngstream. Ниже представлен код примера 3-1 при использовании ostri ngstream вместо spri ntf.

пример 3-2: строковое представление данных в С++ с

использованием ostringstream.

void PrettyFormatC int i, stri ng& s ) {

He так уж понятно и просто:

ostringstream temp;

temp setwC4) i; s = temp.strO ;

Обратите внимание, что использование stri ngstream меняет достоинства и недостатки spri ntf местами.

/. Простота использования и ясность. Как видите, изменения свелись не только к замене одной строки тремя, но и к введению временной переменной: Эта версия кода превосходит предыдущую по ряду параметров, но простота и ясность не входят в их число. Сложность не в том, чтобы изучить все манипуляторы потоком, - в конце концов, это задача той же сложности, что и изучить флаги форматирования sprintf; дело в том, что эти манипуляторы гораздо более громоздкие. Мне кажется, что код с длинными именами, например, setprecisiопС9) и setwC14), читается не так легко, как флаги форматирования в snpri ntf, где то же форматирование достигается при помощи простой строки %14.9, даже если аккуратно отформатировать исходный текст программы.

2. Эффективность (возможность непосредственного использования существующих буферов), stri ngstream работает в дополнительном буфере, так что при его использовании обычно необходимо дополнительное выделение памяти для рабочего буфера и вспомогательных объектов. Я провел небольшой эксперимент, скомпилировав пример 3-2 двумя популярными компиляторами, изменив при этом : :operator new для подсчета выполняемых при работе кода вьщелений памяти. На одной платформе я получил два динамических выделения памяти, а на другой - три.

Однако там, где у spri ntf начинают проявляться недостатки, stri ngstream радует своими достоинствами.

3. Безопасность в плане переполнения буфера. Внутренний буфер basi c stri ngbuf потока stri ngstream автоматически увеличивается, если в этом возникает необходимость.

4. Безопасность типов. Использование перегруженного оператора и разрешения перегрузки обеспечивает корректную работу с разными типами, включая пользовательские типы, которые могут иметь собственные операторы вывода в поток. При ис-



пользовании stringstream никакие ошибки времени выполнения, связанные с несоответствием типов, попросту невозможны.

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

tempiate<typename т>

void PrettyFormatC Т value, string* s ) { ostringstream temp; temp setw(4) value; s = temp. strQ ;

Итак, в результате мы получили следующую таблицу сравнения stringstream и spri ntf.

stringstream

sprintf

Стандартность?

Да: [С-Ь-НОЗ]

Да: [С901, [С-ь+03], [С99]

Простота использования и ясность?

Эффективность, без излишних распределений

памяти?

Безопасность в плане переполнения буфера?

Безопасность типов?

Использование в шаблонах?

Альтернатива №3: std::strstream в) std::strstream

Хорошо это или нет, но в связи с тем, что strstream в стандарте fC++03j называют устаревшим и не рекомендуемым для использования, в книгах по С++ либо в лучшем случае дастся краткое описание этого класса ([Josuttis99]), либо он практически проиг!ю-рирован ([StroustrupOO]), или в книге явно указано, что из-за второсортности strstream его описание отсутствует ([LangerOO]). Однако несмотря на то, что комитет по стандарту С-Ы- отдал предпочтение stri ngstream, в котором лучше инкапсулировано управление памятью, strstream остается официальной частью стандарта, которую обязаны поддерживать все реализации С-Ы-.

Поскольку strstream все еще остается частью стандарта, для полноты рассмотрения мы обязаны изучить этот класс. В случае eio использования пример 3-1 выглядит следующим образом.

пример 3-3: строковое представление данных в С++ с использованием ostrstream.

void PrettyFormatC int i, char* buf, int buflen ) {

Статус strstream - нежелателен (deprecated), что означает, что комитет по стандарту С + + предупреждает: этот класс может исчезнуть из стандарта в любой момент, возможно, уже в след>пошей версии стандарта. Но удалить нечто из стандарта - практически очень сложная задача. Ведь как только та или иная возможность появляется в стандарте, появляется и множество кода с ее использованием, и удаление из стандарта грозит потерей обратной совместимости. Даже при официальном удалении чего-либо из стандарта конкретные реализации зачастую продолжают поддерживать это в целях обеспечения обратной совместимости. Нередко неже.чатель-ные возможности так никогда и не удаляются из стандарта. Так, в стандарте Fonran они присутствуют десятилетиями.



1 2 3 4 [ 5 ] 6 7 8 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика