I have written a C program which works perfectly on linux, but when I compile it on windows, it gives me an error saying that asprintf() is undefined. It should be a part of the stdio library but it seems that many compilers do not include it. Which compiler can I use for windows which will allow me to use the asprintf() function? I have tried multiple compilers and none seem to define it so far.
The asprintf() function is not part of the C language and it is not available on all platforms. The fact that Linux has it is unusual.
You can write your own using _vscprintf and _vsprintf_s.
int vasprintf(char **strp, const char *fmt, va_list ap) {
// _vscprintf tells you how big the buffer needs to be
int len = _vscprintf(fmt, ap);
if (len == -1) {
return -1;
}
size_t size = (size_t)len + 1;
char *str = malloc(size);
if (!str) {
return -1;
}
// _vsprintf_s is the "secure" version of vsprintf
int r = _vsprintf_s(str, len + 1, fmt, ap);
if (r == -1) {
free(str);
return -1;
}
*strp = str;
return r;
}
This is from memory but it should be very close to how you would write vasprintf for the Visual Studio runtime.
The use of _vscprintf and _vsprintf_s are oddities unique to the Microsoft C runtime, you wouldn't write the code this way on Linux or OS X. The _s versions in particular, while standardized, in practice are not often encountered outside the Microsoft ecosystem, and _vscprintf doesn't even exist elsewhere.
Of course, asprintf is just a wrapper around vasprintf:
int asprintf(char **strp, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vasprintf(strp, fmt, ap);
va_end(ap);
return r;
}
This is not a "portable" way to write asprintf, but if your only goal is to support Linux + Darwin + Windows, then this is the best way to do that.
Multiplatform implementation of asprintf()
Based on answers by @DietrichEpp and @MarcusSun in this thread and this collaborative implementation of _vscprintf() for MacOS/Linux in another thread. Tested on GCC/Linux, MSVC/Windows, MinGW/Windows (TDM-GCC via Code::Blocks). Should hopefully work on Android too.
Header file
(Presumably named asprintf.h.)
#include <stdio.h> /* needed for vsnprintf */
#include <stdlib.h> /* needed for malloc-free */
#include <stdarg.h> /* needed for va_list */
#ifndef _vscprintf
/* For some reason, MSVC fails to honour this #ifndef. */
/* Hence function renamed to _vscprintf_so(). */
int _vscprintf_so(const char * format, va_list pargs) {
int retval;
va_list argcopy;
va_copy(argcopy, pargs);
retval = vsnprintf(NULL, 0, format, argcopy);
va_end(argcopy);
return retval;}
#endif // _vscprintf
#ifndef vasprintf
int vasprintf(char **strp, const char *fmt, va_list ap) {
int len = _vscprintf_so(fmt, ap);
if (len == -1) return -1;
char *str = malloc((size_t) len + 1);
if (!str) return -1;
int r = vsnprintf(str, len + 1, fmt, ap); /* "secure" version of vsprintf */
if (r == -1) return free(str), -1;
*strp = str;
return r;}
#endif // vasprintf
#ifndef asprintf
int asprintf(char *strp[], const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vasprintf(strp, fmt, ap);
va_end(ap);
return r;}
#endif // asprintf
Usage
#include <stdio.h> /* needed for puts */
#include <stdlib.h> /* needed for free */
#include "asprintf.h"
int main(void) {
char *b;
asprintf(&b, "Mama %s is equal %d.", "John", 58);
puts(b); /* Expected: "Mama John is equal 58." */
free(b); /* Important! */
return 0;
}
Live examples: rex (MSVC · gcc · clang) | repl.it | tio.run | Codepad | ide1 (gcc · clang · C99)
Based on the answer provided by 7vujy0f0hy, here is a header file providing asprintf, vasprintf and vscprintf for multiple platforms/compilers (GNU-C-compatible compilers + MSVC). Please note that this requires C99 due to the use of va_copy. Refer to the links below to test a slightly modified version of this code using online compilers.
asprintf.h:
#ifndef ASPRINTF_H
#define ASPRINTF_H
#if defined(__GNUC__) && ! defined(_GNU_SOURCE)
#define _GNU_SOURCE /* needed for (v)asprintf, affects '#include <stdio.h>' */
#endif
#include <stdio.h> /* needed for vsnprintf */
#include <stdlib.h> /* needed for malloc, free */
#include <stdarg.h> /* needed for va_* */
/*
* vscprintf:
* MSVC implements this as _vscprintf, thus we just 'symlink' it here
* GNU-C-compatible compilers do not implement this, thus we implement it here
*/
#ifdef _MSC_VER
#define vscprintf _vscprintf
#endif
#ifdef __GNUC__
int vscprintf(const char *format, va_list ap)
{
va_list ap_copy;
va_copy(ap_copy, ap);
int retval = vsnprintf(NULL, 0, format, ap_copy);
va_end(ap_copy);
return retval;
}
#endif
/*
* asprintf, vasprintf:
* MSVC does not implement these, thus we implement them here
* GNU-C-compatible compilers implement these with the same names, thus we
* don't have to do anything
*/
#ifdef _MSC_VER
int vasprintf(char **strp, const char *format, va_list ap)
{
int len = vscprintf(format, ap);
if (len == -1)
return -1;
char *str = (char*)malloc((size_t) len + 1);
if (!str)
return -1;
int retval = vsnprintf(str, len + 1, format, ap);
if (retval == -1) {
free(str);
return -1;
}
*strp = str;
return retval;
}
int asprintf(char **strp, const char *format, ...)
{
va_list ap;
va_start(ap, format);
int retval = vasprintf(strp, format, ap);
va_end(ap);
return retval;
}
#endif
#endif // ASPRINTF_H
example.c:
#include "asprintf.h" /* NOTE: this has to be placed *before* '#include <stdio.h>' */
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *str = NULL;
int len = asprintf(&str, "The answer to %s is %d", "life, the universe and everything", 42);
if (str != NULL) {
printf("String: %s\n", str);
printf("Length: %d\n", len);
free(str);
}
return 0;
}
Test using online compilers:
rextester C (gcc) | rextester C (clang) | rextester C (msvc)
asprintf() is not a C standard function. It's a GNU extension provided by glibc. Hence it works on Linux. But other C implementations may not provide it -- which appears to be the case with your library.
You can instead rewrite your code using standard C functions malloc() and snprintf().
This function is in glibc libary and not supported by Windows.
As far as I knew, asprintf is similiar to sprintf with buffer allocation in it.
In windows, the simplest way is probably to write your own implementation. To calculate the size of buffer to be allocated, just use something like:
int size_needed = snprintf(NULL, 0, "%s\n", "test");
Once the size is calcuated, just allocate buffer, call snprintf to format string and return pointer.
GNU libiberty
Licensed under the LGPL this library includes an implementation of asprintf().
“Possibly the easiest way to use libiberty in your projects is to drop the libiberty code into your project’s sources.”1
int asprintf (char **resptr, const char *format, ...)
Like sprintf, but instead of passing a pointer to a buffer, you pass a pointer to pointer. This function will compute the size of the buffer needed, allocate memory with malloc, and store a pointer to the allocated memory in *resptr. The value returned is the same as sprintf would return. If memory could not be allocated, minus one is returned and NULL is stored in *resptr.
来源:https://stackoverflow.com/questions/40159892/using-asprintf-on-windows