Используя snprintf для предотвращения переполнения буфера

По моему опыту, при записи главным образом приложений для Клиента/сервера WinForms это простые заключения, в которые я приехал:

Хранимые процедуры Использования:

  1. Для любой сложной работы данных. Если Вы собираетесь быть выполнением чего-то действительно требование курсора или временных таблиц, это является обычно самым быстрым, чтобы сделать это в SQL Server.
  2. , Когда необходимо заблокировать вниз доступ к данным. Если Вы не предоставляете доступ таблицы к пользователям (или роль, или безотносительно) можно быть уверены, что единственный способ взаимодействовать с данными через SP, который Вы создаете.

специальные запросы Использования:

  1. Для CRUD, когда Вы не должны ограничивать доступ к данным (или делают так другим способом).
  2. Для простых поисков. Создание SP для набора критериев поиска является болью и трудный поддержать. Если можно генерировать довольно быстрое использование поискового запроса это.

В большинстве моих приложений я использовал и и специальный sql SP, хотя я нахожу, что использую SP все меньше и меньше, поскольку они заканчивают тем, что были кодом точно так же, как C#, только тяжелее к управлению версиями, тесту, и поддерживают. Я рекомендовал бы использовать специальный sql, если Вы не можете найти определенную причину не к.

17
задан Peter Mortensen 11 April 2018 в 10:36
поделиться

6 ответов

Как уже говорили другие, в этом случае вам не понадобится -1. Если размер массива фиксированный, я бы использовал вместо него strncpy . Он был сделан для копирования строк - sprintf был сделан для сложного форматирования. Однако, если размер массива неизвестен или вы пытаетесь определить, сколько памяти необходимо для форматированной строки. Это то, что мне действительно нравится в стандартной версии snprintf :

char* get_error_message(char const *msg) {
    size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
    char  *buffer = malloc(needed+1);
    sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
    return buffer;
}

Объедините эту функцию с va_copy , и вы сможете создавать очень безопасные операции с форматированными строками.

28
ответ дан 30 November 2019 в 10:36
поделиться

Вам не нужно -1, поскольку в ссылке указано:

Функции snprintf () и vsnprintf () не писать больше, чем размер в байтах (включая конечный '\ 0').

Обратите внимание на "включая завершающую '\ 0'" часть

12
ответ дан 30 November 2019 в 10:36
поделиться

Нет необходимости в -1. C99 snprintf всегда завершается нулем. Аргумент размера определяет размер выходного буфера , включая нулевой терминатор . Таким образом, код становится

char err_msg[32];
int ret = snprintf(err_msg, sizeof err_msg, "[ ST_ENGINE_FAILED ]");

ret содержит фактическое количество напечатанных символов ( без нулевого терминатора).

Однако, не путайте с Microsoft _snprintf (pre-C99), который не завершает нуль, и, в этом отношении, имеет совершенно другое поведение (например, возвращает -1 вместо предполагаемой длины в случае, если буфер недостаточно велик). Если вы используете _snprintf , вы должны использовать тот же код, что и в вашем вопросе.

9
ответ дан 30 November 2019 в 10:36
поделиться

В данном примере вам следует сделать следующее:

char err_msg[32];
strncpy(err_msg, "[ ST_ENGINE_FAILED ]", sizeof(err_msg));
err_msg[sizeof(err_msg) - 1] = '\0';

или даже лучше:

char err_msg[32] = "[ ST_ENGINE_FAILED ]";
1
ответ дан 30 November 2019 в 10:36
поделиться

Согласно snprintf (3) :

Функции snprintf () и vsnprintf () не пишут больше размера байт (включая завершающий '\ 0' ).

3
ответ дан 30 November 2019 в 10:36
поделиться

sizeof вернет количество байтов, которое тип данных будет использовать в памяти, а не длину строки. Например, sizeof (int) возвращает 4 байта в 32-битной системе (ну, я думаю, в зависимости от реализации). Поскольку вы используете константу в своем массиве, вы можете передать ее в printf.

-1
ответ дан 30 November 2019 в 10:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: