Здравствуйте, Dair, Вы писали:
D>std::string formatString(const char* format, ...) D>Берёт строчку-форматтер в формате printf, при помощи vsnprintf подставляет в неё параметры, отдаёт std::string на выходе.
Кстати. Буфер фиксированного размера? Он адаптируется под конкретный вызов?
Насколько я вижу, в Android NDK торековский stdio. В этом случае, вместо snprintf() полезнее fwopen()+fprintf(), а коллбэк в fwopen() пусть расширяет целевую строку (std::string) на пришедшую порцию. Где-то так:
static int addPortion(void* cookie, const char *portion, int plen) {
std::string* tp = (std::string*) cookie;
tp->append(portion, plen);
return plen;
}
size_t formatString(std::string& target, const char* format, ...) {
FILE* fw = fwopen(&target, addPortion);
va_list ap;
va_start(ap, format);
size_t ret = vfprintf(fw, format, ap);
va_end(ap);
fclose(fw);
return ret;
}
Здравствуйте, Dair, Вы писали:
D>Присказка: D>Сегодня клиент из Поднебесной пишет, что в некотором месте игра на Android 4 работает, а на 6.0.1 — не работает. D>... D>Как править — понятно. Но сам факт.
Здравствуйте, Dair, Вы писали:
D>В моём случае в эту функцию отдаётся формат и один строковый параметр. Но в формате нет никакого %s — особенности китайской локализации. D>Согласно стандарта, функция должна бы просто вернуть строчку-формат, забыв про аргумент.
D>Так и происходит на Android4.
D>В мане пишут: D>[q]Concerning the return value of snprintf(), SUSv2 and C99 contradict each other: when snprintf() is called with size=0 then SUSv2 stipulates an unspecified return value less than 1, while C99 allows str to be NULL in this case, and gives the return value (as always) as the number of characters that would have been written in case the output string has been large enough. [/b]
Ты вообще заметил, что пишешь о разных вещах? Процитированный кусок это реакция на указатель на целевой буфер, равный NULL, при bufsize==0, а перед этим ты говорил про форматную строку и первый позиционный параметр в varargs.
D>Но на SUSv2 всегда было покласть — это стандарт каких-то толстых юниксов типа Solaris, которые нашей таргет-платформой никогда не были.
SUSv2 был стандартом для всех юниксов, хоть многие и не успели догнать. Ты путаешь с SVID, OSF/1 и тому подобными. Но если ты уж взялся обсуждать случай целевого буфера, равного NULL, то уже начиная с исходного POSIX.1-2001 это явно разрешено в нынешнем виде ("aligned with C99").
D>А на Android6 (на Android5 не проверял, но, вроде, так же как и на 6) vsnprintf(NULL, 0, ...) возвращает 1, и, впоследствии, записывает туда пустую строку (один только 0).
D>Как править — понятно. Но сам факт.
Если ты ничего не попутал, то одновременное нарушение C99 и POSIX это 100% баг, и обязаны вылечить. Но рассказ про отсутствие %s заставляет думать, что тебе надо тщательнее перепроверить свои выводы.
Присказка:
Сегодня клиент из Поднебесной пишет, что в некотором месте игра на Android 4 работает, а на 6.0.1 — не работает.
Полез разбираться.
Взял два Android-телефона, на одном 4.4.2, на другом — 6.
Баг воспроизводится.
Удивительно — думаю я. В конкретно этом месте к OS какой бы то ни было вообще обращений нет. Один и тот же код одинаково работает на iOS, Android, Win32, Win8/10, OS X.
Поскольку у меня нет настроенного окружения для отладки C++ под Android, отлаживаюсь дебажным выводом.
Сказка:
Есть у нас в игре функция общего назначения, используемая и в хвост и в гриву:
std::string formatString(const char* format, ...)
Берёт строчку-форматтер в формате printf, при помощи vsnprintf подставляет в неё параметры, отдаёт std::string на выходе.
В моём случае в эту функцию отдаётся формат и один строковый параметр. Но в формате нет никакого %s — особенности китайской локализации.
Согласно стандарта, функция должна бы просто вернуть строчку-формат, забыв про аргумент.
Так и происходит на Android4.
В мане пишут:
[q]Concerning the return value of snprintf(), SUSv2 and C99 contradict each other: when snprintf() is called with size=0 then SUSv2 stipulates an unspecified return value less than 1, while C99 allows str to be NULL in this case, and gives the return value (as always) as the number of characters that would have been written in case the output string has been large enough. [/b]
Но на SUSv2 всегда было покласть — это стандарт каких-то толстых юниксов типа Solaris, которые нашей таргет-платформой никогда не были.
А на Android6 (на Android5 не проверял, но, вроде, так же как и на 6) vsnprintf(NULL, 0, ...) возвращает 1, и, впоследствии, записывает туда пустую строку (один только 0).
Здравствуйте, netch80, Вы писали:
N>Если ты ничего не попутал, то одновременное нарушение C99 и POSIX это 100% баг, и обязаны вылечить. Но рассказ про отсутствие %s заставляет думать, что тебе надо тщательнее перепроверить свои выводы.
ok, у меня пропадает суббота на исследования.
Да, я не знаю, кто виновен — отсутствие форматтера в формате или нули в первых параметрах — итерация "компиляция — инсталляция — запуск" для меня около 5 минут, очень долго.
Здравствуйте, netch80, Вы писали: N>Здравствуйте, Dair, Вы писали: D>>std::string formatString(const char* format, ...) D>>Берёт строчку-форматтер в формате printf, при помощи vsnprintf подставляет в неё параметры, отдаёт std::string на выходе. N>Кстати. Буфер фиксированного размера? Он адаптируется под конкретный вызов?
Происходит два вызова vsnprintf. Первый — vsnprintf(NULL, 0, format, ...) — возвращает размер нужного буфера. Этот буфер и выделяется, и в него вызывается второй раз vsnprintf. N>Насколько я вижу, в Android NDK торековский stdio. В этом случае, вместо snprintf() полезнее fwopen()+fprintf(), а коллбэк в fwopen() пусть расширяет целевую строку (std::string) на пришедшую порцию. Где-то так:
Здравствуйте, Dair, Вы писали:
D>Прикольно. Сейчас посмотрю, есть ли такое под виндой и iOS, гугл пока не справился.
Под виндой — 100% нет — там stdio отстал лет на 30.
Под iOS — вероятно, BSD userland => большие шансы на Torek stdio.
Под Linux (в общем) вместо fwopen — fopencookie и коллбэк чуть другой.
Здравствуйте, Dair, Вы писали:
D>>>Как править — понятно. Но сам факт.
M>>Ты еще покури на бочке пороха — тоже удивишься
D>В смысле? Тот, кто писал функцию, полагался на стандарт.