weiss / c99-snprintf Goto Github PK
View Code? Open in Web Editor NEWPortable implementation of snprintf(3), vsnprintf(3), asprintf(3), and vasprintf(3)
Home Page: http://www.jhweiss.de/software/snprintf.html
License: Other
Portable implementation of snprintf(3), vsnprintf(3), asprintf(3), and vasprintf(3)
Home Page: http://www.jhweiss.de/software/snprintf.html
License: Other
README file for C99-snprintf ============================ OVERVIEW -------- C99-snprintf provides a portable implementation of snprintf(3), vsnprintf(3), asprintf(3), and vasprintf(3). It should be fully C99 compliant, with the exceptions that it doesn't provide wide character support and that "%a" and "%A" conversions aren't supported. C99-snprintf should be buildable with any ANSI C compiler, it doesn't require libc functionality other than malloc(3) (for vasprintf(3)) and the stdarg(3) or varargs(3) macros, and it has no other prerequisites. The snprintf(3) and vsnprintf(3) functions are part of the C99 standard library. However, snprintf(3) and vsnprintf(3) weren't included in the C89/C90 standards and some systems don't provide C99 compliant implementations of these functions. For example, if the ouput buffer isn't big enough to hold the full conversion result, IRIX up to the current release 6.5.30 and glibc up to 2.0.x don't return the same value as with a sufficiently sized buffer (which makes it impossible to precompute the required buffer size), and some older systems (such as 64-bit Solaris 7) ignore the specified buffer size and overrun the buffer if it's too small. The asprintf(3) and vasprintf(3) functions aren't standardized at all. They're included with recent releases of glibc and BSD's libc, but they aren't available on other systems, such as System V (e.g., Solaris). So, if any of these functions are used, portable software should include replacement code which is used in case the functions aren't available or don't work correctly on the target system. C99-snprintf can be included with software packages in order to provide such replacement functions. USAGE ----- 1) Add snprintf.c to your project files. If you're using GNU Automake, you could use a line such as "foo_LDADD = $(LIBOBJS)" (where "foo" is the name of your program) in your Makefile.am. 2) Add snprintf.m4 to your m4 include directory or to your acinclude.m4 file. If you're using neither, you can simply include the contents of snprintf.m4 in your configure.ac file. 3) For each replacement function which might be needed in your project, call the according Autoconf macro in your configure.ac file. That is, in order to have all four replacement functions available if needed: HW_FUNC_VSNPRINTF HW_FUNC_SNPRINTF HW_FUNC_VASPRINTF HW_FUNC_ASPRINTF 4) The required replacement functions should be declared in some header file included throughout your project files: #if HAVE_CONFIG_H #include <config.h> #endif #if HAVE_STDARG_H #include <stdarg.h> #if !HAVE_VSNPRINTF int rpl_vsnprintf(char *, size_t, const char *, va_list); #endif #if !HAVE_SNPRINTF int rpl_snprintf(char *, size_t, const char *, ...); #endif #if !HAVE_VASPRINTF int rpl_vasprintf(char **, const char *, va_list); #endif #if !HAVE_ASPRINTF int rpl_asprintf(char **, const char *, ...); #endif #endif /* HAVE_STDARG_H */ USAGE WITHOUT GNU AUTOCONF -------------------------- If you're not using GNU Autoconf, omit the steps 2 and 3 from the above instructions. Instead: 1) The following preprocessor macros should be defined to 1 if the feature or file in question is available on the target system (though basic functionality should be available as long as HAVE_STDARG_H is defined correctly): HAVE_VSNPRINTF HAVE_SNPRINTF HAVE_VASPRINTF HAVE_ASPRINTF HAVE_STDARG_H HAVE_STDDEF_H HAVE_STDINT_H HAVE_STDLIB_H HAVE_FLOAT_H HAVE_INTTYPES_H HAVE_LOCALE_H HAVE_LOCALECONV HAVE_LCONV_DECIMAL_POINT HAVE_LCONV_THOUSANDS_SEP HAVE_LONG_DOUBLE HAVE_LONG_LONG_INT HAVE_UNSIGNED_LONG_LONG_INT HAVE_INTMAX_T HAVE_UINTMAX_T HAVE_UINTPTR_T HAVE_PTRDIFF_T HAVE_VA_COPY HAVE___VA_COPY 2) The calls to the functions which should be replaced must be redefined throughout the project files: #define vsnprintf rpl_vsnprintf #define snprintf rpl_snprintf #define vasprintf rpl_vasprintf #define asprintf rpl_asprintf BUGS AND CAVEATS ---------------- Depending on the size of the largest integer type available on the target platform, floating point precisions larger than 9, 19, or 38 are not supported. If a larger precision is specified, it will silently be reduced to the largest possible precision on the target system. If the integral part of a floating point value doesn't fit into the largest integer type available on the target platform, the conversion will fail. In this case, C99-snprintf will return -1 and set the global variable errno to indicate the error. The same is done if the specified field width or precision are (or if the return value would be) larger than INT_MAX. C99-snprintf makes a few assumptions regarding integer (and pointer value) conversions which aren't backed by the C standard, but which should be safe in practice. FEEDBACK -------- Please let me know if you have any comments or bug reports regarding C99-snprintf: Holger Weiss <[email protected]> # vim: set joinspaces textwidth=72 filetype=none:
As reported by modelica/ModelicaStandardLibrary#2626, is
VA_START(ap, format);
missing before the call of VA_COPY in rpl_vasprintf?
Lines 1492 to 1494 in 27b59ac
There has not been any new release since v1.1 from 2008. Is there any chance to have a new released version to get the changes from 2014 also in downstream repos, that still depend on v1.1? Thanks a lot?
Coverity Scan reports an Overflowed return value from function myround
.
static UINTMAX_T
myround(LDOUBLE value)
{
UINTMAX_T intpart = cast(value);
//1. Condition (value -= intpart) < 0.5, taking false branch.
//2. overflow: Add operation overflows on operands intpart and 1UL.
//CID 59973 (#1 of 1): Overflowed return value (INTEGER_OVERFLOW)
//3. overflow_sink: Overflowed or truncated value (or a value computed from an overflowed or truncated value) ((value -= intpart) < 0.5) ? intpart : (intpart + 1UL) used as return value.
return ((value -= intpart) < 0.5) ? intpart : intpart + 1;
}
Is there a known upper and lower bounds of the exponent, or a LDOUBLE_MAX variable or equivalent (maybe DBL_MAX)? If so, then we could protect against overflow.
The cast() function test against INTMAX_MAX for this very reason.
Visual Studio 2010 prints the C4244 conversion warnings on warning level /W3
snprintf.c(1184): warning C4244: '=': Konvertierung von 'long double' in 'unsigned long', möglicher Datenverlust
snprintf.c(1436): warning C4244: '=': Konvertierung von 'long double' in 'unsigned long', möglicher Datenverlust
Visual Studio 2010 prints the C4267 conversion warnings on warning level /W3
snprintf.c(723): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(768): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(858): warning C4267: '=': Konvertierung von 'size_t' nach 'char', Datenverlust möglich
snprintf.c(862): warning C4267: '=': Konvertierung von 'size_t' nach 'short', Datenverlust möglich
snprintf.c(866): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(870): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(885): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(889): warning C4267: '=': Konvertierung von 'size_t' nach 'long', Datenverlust möglich
snprintf.c(893): warning C4267: '=': Konvertierung von 'size_t' nach 'int', Datenverlust möglich
It turns out that the tests fail on linux on Intel if you add the following code:
void
set_fpu (unsigned int mode)
{
asm ("fldcw %0" : : "m" (*&mode));
}
and then
set_fpu(x27f);
at the start of main. This (according to https://www.linuxtopia.org/online_books/an_introduction_to_gcc/gccintro_70.html ) sets excess precision to be disabled. This makes it compatible with other platforms that do not support excess precision.
Indeed, the results that I then get from x86 compare to those that I get from a microcontroller platform.
The failed tests seem to indicate that the system sprintf
is doing something different. The worst cases appear to be with very small exponents. For example:
Results don't match, format string: %.16e
sprintf(3): [1.6784992078596053e-265] (23)
snprintf(3): [1.6784992078596017e-265] (23)
Results don't match, format string: %.16e
sprintf(3): [1.6784992078596089e-265] (23)
snprintf(3): [1.6784992078596053e-265] (23)
I am a bit puzzled by the fact that the x86 code is using long double
and the microcontroller platform is not.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.