2х вызов snprintf()
является распространенной идиомой.
... есть другая проблема?
Проблемы лежат по углам
Ведение формата
Ниже приведен повторяющийся формат, склонный к разрыву по мере старения кода, и только одна строка изменяется.
// Oops!
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1;
char *const str = malloc(need_space * sizeof(char));
int written = snprintf(str, need_space, "abs %s ", "fgh");
Вы заметили разницу?
Лучше один раз указать формат.
#define FMT_ABS_S "abs %s"
int need_space = snprintf(NULL, 0, FMT_ABS_S, "fgh");
char *const str = malloc(sizeof *str * (need_space + 1u));
int written = snprintf(str, need_space, FMT_ABS_S, "fgh");
Волатильность
Код должен гарантировать, что значения не изменяются (не volatile
) между двумя вызовами, и в многопоточных приложениях возникают особые проблемы.
Ошибка проверки
В коде отсутствуют проверки. Но даже с проверками, как справиться с неожиданными результатами - возможно, просто под залог?
static const char *fmt_s = "abs %s";
int need_space = snprintf(NULL, 0, fmt_s, "fgh");
if (need_space < 0) {
Handle_EncodingError();
}
char *const str = malloc(sizeof *str * (need_space + 1u));
if (str == NULL) {
Handle_OutOfMemory();
}
int written = snprintf(str, need_space, fmt_s, "fgh");
if (written < 0 || written > need_space) {
Handle_Error();
}
Пройдя дважды, хотя
2 звонка могут быть бесполезными в некоторых ситуациях, но обычно воздействие оказывается меньше, чем предполагалось. @ Джонатан Леффлер
Тем не менее, для меня «что делать, если выделение не удастся», в любом случае является ограничителем показа, и код сообщает об ошибке и, возможно, завершается.
Выборочно достаточно одного раза
Когда формат s*printf()
строго контролируется, я считаю достаточным 1 вызов.
// int to string
#define LOG2_N 28
#define LOG2_D 93
// Number of char needed for a string of INT_MIN is log10(bit width) + 3
#define INT_LEN ((sizeof(int)*CHAR_BIT-1)*LOG2_N/LOG2_D + 3)
char s[INT_LEN * 2]; // I like to use 2x to handle locale issues, no need to be stingy here.
int len = snprintf(s, sizeof s, "%d", i);
if (len < 0 || len >= sizeof s) {
Handle_VeryUnusualFailure();
}