A combined function for fprintf and write in c/c++ - c++

In C/C++, there is a 'write() function which let me write to either file or a socket, I just pass in the file descriptor accordingly). And there is a fprintf() which allow me to do fprintf (myFile, "hello %d", name); but it only works for file.
Is there any api which allows me to do both?
i.e. able to let me do print formatting and able to switch between writing to file or socket?
Thank you.

Sure: just use fdopen on the socket to create a FILE* stream, and use fprintf appropriately.

In C, on POSIX-ish machines (which you must have to be using 'write()'), you can use:
fdopen() to create a file stream from a file descriptor.
fileno() to obtain a file descriptor from a file stream.
You need to be careful about flushing the file stream at appropriate times before using the matching file descriptor.

You can use sprintf or snprintf to print to a char * buffer, and then use write. To get a file descriptor from a FILE * variable, you can use fileno. There is no portable way to go from a file descriptor to a FILE *, though: you can portably to use fdopen to associate a FILE * with a valid file descriptor.
In addition, the latest POSIX standard specifies dprintf, but the GNU libc dprintf man page has this to say:
These functions are GNU extensions, not in C or POSIX. Clearly, the
names were badly chosen. Many systems (like MacOS) have incompatible
functions called dprintf(), usually some debugging version of printf(),
perhaps with a prototype like
void dprintf (int level, const char *format, ...);
where the first parameter is a debugging level (and output is to
stderr). Moreover, dprintf() (or DPRINTF) is also a popular macro name
for a debugging printf. So, probably, it is better to avoid this function in programs intended to be portable.
Of course, the libc manual page is not updated with the latest standard in mind, but you still have to be careful with using dprintf, since you might get something you don't want. :-)

You can do something like this, maybe :
#include <stdarg.h>
int fdprintf(int fd, const char* fmt, ...) {
char buffer[4096] = {0};
int cc;
va_list args;
va_start(args, fmt);
if ((cc = vsnprintf(buffer, 4096, fmt, args)) > 0) {
write(fd, buffer, cc);
}
va_end(args);
return cc;
}

generalizing tusbar answer, and to make it work with visual studio you can try the following codes:
`
int fdprintf(int fd, const char* fmt, ...) {
int cc;
va_list args;
va_start(args, fmt);
int len = _vscprintf(fmt,args) + 1;
char* buffer = new char[len];
buffer[len] = 0;
if ((cc = vsprintf_s(buffer, len-1, fmt, args)) > 0) {
write(fd, buffer, cc);
}
va_end(args);
delete[] buffer;
return cc;
}
`

Related

How to properly replace sprintf_s by sprintf in C++03?

sprintf_sis a Microsoft implementation of the function sprintf where they patched a flaw, adding an argument to take a boundary value where the function is limited to write.
An equivalent was introduced in C++11: snprintf. But here, we are talking of C++03 syntax.
Signatures:
count_char_written sprintf(char* string_out, const char* output_template, VARIADIC_ARGS);
// and
count_char_written sprintf_s(char* string_out, size_t buffer_max_size, const char* output_template, VARIADIC_ARGS);
Functionnaly, sprintf_s is more advanced than sprintf, because it avoids overflows.
But sprintf_s is Microsoft only!
What to do if you want to port back a C++03 code written with sprintf_s to POSIX compatible syntax?
Today both snprintf and vsnprintf should be available everywhere with the exception of Windows with MSVC12 and older. The simplest way for you is to provide snprintf/vsnprintf on Windows where it is not available.
Windows provides function _vsnprintf_s which is already similar to vsnprintf, but has following important differences with regards to what happens when provided buffer is too small:
Buffer content depends on the additional count argument which does not exist in vsnprintf. To get vsnprintf behavior you can pass _TRUNCATE here.
-1 is returned instead of number of characters required. This can be fixed by using _vscprintf function which only needs to be called if previous call to _vsnprintf_s has failed.
Additionally those functions do not support format specifiers added in C99 such as %zd. This cannot be easily resolved, you will have to avoid using them.
Code below:
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int r = -1;
if (size != 0)
{
va_list args_copy;
va_copy(args_copy, args);
r = _vsnprintf_s(buf, size, _TRUNCATE, fmt, args_copy);
va_end(args_copy);
}
if (r == -1)
{
r = _vscprintf(fmt, args);
}
return r;
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int r = vsnprintf(buf, size, fmt, args);
va_end(args);
return r;
}
Note: Windows also provides _vsnprintf which looks better suited for this implementation, but it does not terminate the resulting string. If you want to use it, you should be careful.

vsnprintf and gcc

I have the following statement:
vsnprintf(target, size - 1, "%ls_%ls", str16_1, str16_2);
Why does this fail on gcc?
I used this on Windows like this:
vsnprintf(target, size - 1, "%S_%S", str16_1, str16_2);
and it's working as expected. On gcc documentation I found that %S is synonym with %ls, but I must not use it. I tried also with %S, but is not working. I use this in a function with variable argument list. Is it possible to not work because I change the format variable that I pass to va_start? I must search %S and replace it with %ls in format variable.
The function is something like:
void f(const char* format, ...){
char* new_format = format with %S replaced with %ls;
va_list argptr;
va_start(args, format);
vsnprintf(str, size-1, new_format, argptr);
}
I checked and new_format is correct.
Thank you!
Try using snprintf, the reason being vsnprintf. vsnprintf takes an argument of type va_list, not a literal variadic argument list. For example:
va_list ap;
va_start (ap, first_arg_in_this_function);
vsnprintf (buf, size, format_str, ap);
va_end (ap);
Whereas with sprintf:
snprintf (buf, size, format_str, x, y);
Use v*printf when...
Making wrappers around printf style functions
Variadic macros are not an option
Otherwise just use *printf
Your use of va_start is incorrect. In this statement:
va_start(args, new_format);
you are not referring to the format parameter of the f() function. The second argument to va_start() must refer to a parameter in the formal parameter list of the function. Anything else is likely undefined behaviour.
The compiler uses the named formal parameter in va_start() to determine where to start looking for the variable argument list in the function call. It doesn't automatically know where you put ... in the argument list (perhaps you might expect that it should, but that's not how it works).
I looked up %ls for vsnprintf and found that this is the format specifier for printing/formatting a string of wide characters i.e. wide_t *p = L"Hello world!";
It took a bit of playing and googling wide character usage in C++ (I liked the following page: http://www.linux.com/archive/feed/51836), but I think I figured out your problem.
If you pass in a char string to %ls then it doesn't expand, but if you pass in a wchar_t string to %ls then it prints.
Consider the following example code I based on your information:
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
char str[100];
void f (const char *format,
...)
{
va_list args;
va_start(args, format);
vsnprintf(str, sizeof(str), format, args);
va_end(args);
}
int
main ()
{
char *p1 = "1234";
char *p2 = "abcd";
wchar_t *pw1 = L"9876";
wchar_t *pw2 = L"wxyz";
f("%d_%d", 120, 199);
printf("numbers: %s\n", str);
f("%s_%s", p1, p2);
printf("char*: %s\n", str);
f("%ls_%ls", p1, p2);
printf("wide char* with char* input: %s\n", str);
f("%ls_%ls", pw1, pw2);
printf("wide char* with wide char* input: %s\n", str);
return (0);
}
I compiled this with g++.
make newtest.exe
g++ -g -c -MD -Wall -Werror newtest.cxx
g++ -o newtest.exe newtest.o -lc -lrt
Compilation finished at Thu Jul 29 08:54:57
Output is below:
[SUSE10.1]:201> newtest.exe
numbers: 120_199
char*: 1234_abcd
wide char* with char* input:
wide char* with wide char* input: 9876_wxyz
Use snprintf.
What is your valist type? The correct type for variable list arguments is va_list with an underscore, no?
Because I use this on Mac I found a work-around:
How to "pass on" a variable number of arguments to NSString's +stringWithFormat:
It seems that vsnprintf can't handle 16 bits string. Maybe because wchar_t isn't 16 bits.

Is it possible to pass a C ellipsis call through directly?

void printLine(const wchar_t* str, ...)
{
// have to do something to make it work
wchar_t buffer[2048];
_snwprintf(buffer, 2047, ????);
// work with buffer
}
printLine(L"%d", 123);
I tried
va_list vl;
va_start(vl,str);
and things like this but I didn't find a solution.
Here's a simple C code that does this, you will have to include stdarg.h for this to work.
void panic(const char *fmt, ...){
char buf[50];
va_list argptr; /* Set up the variable argument list here */
va_start(argptr, fmt); /* Start up variable arguments */
vsprintf(buf, fmt, argptr); /* print the variable arguments to buffer */
va_end(argptr); /* Signify end of processing of variable arguments */
fprintf(stderr, buf); /* print the message to stderr */
exit(-1);
}
The typical invocation would be
panic("The file %s was not found\n", file_name); /* assume file_name is "foobar" */
/* Output would be:
The file foobar was not found
*/
Hope this helps,
Best regards,
Tom.
What you want to use is vsprintf it accepts the va_list argument and there is sample
code on MSDN in the link.
EDIT:
You should consider _vsnprintf which will help avoid buffer overrun issues that vsprintf will happily create.
Typically one calls into a variable args version of the function, that accepts va_list. For example _snwprintf internally calls _vsnwprintf; try calling that.
Other people have already pointed you to the vprintf-family of functions, but this also (not surprisingly) is answered by the comp.lang.c FAQ, if you want to familiarize yourself with the other FAQ entries. (They're worth reading, IMO.)
How can I write a function that takes a format string and a variable number of arguments, like printf, and passes them to printf to do most of the work?

How to pass variable number of arguments to printf/sprintf

I have a class that holds an "error" function that will format some text. I want to accept a variable number of arguments and then format them using printf.
Example:
class MyClass
{
public:
void Error(const char* format, ...);
};
The Error method should take in the parameters, call printf/sprintf to format it and then do something with it. I don't want to write all the formatting myself so it makes sense to try and figure out how to use the existing formatting.
Use vfprintf, like so:
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
This outputs the results to stderr. If you want to save the output in a string instead of displaying it use vsnprintf. (Avoid using vsprintf: it is susceptible to buffer overflows as it doesn't know the size of the output buffer.)
have a look at vsnprintf as this will do what ya want http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/
you will have to init the va_list arg array first, then call it.
Example from that link:
/* vsprintf example */
#include <stdio.h>
#include <stdarg.h>
void Error (char * format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer, 255, format, args);
//do something with the error
va_end (args);
}
I should have read more on existing questions in stack overflow.
C++ Passing Variable Number of Arguments is a similar question. Mike F has the following explanation:
There's no way of calling (eg) printf
without knowing how many arguments
you're passing to it, unless you want
to get into naughty and non-portable
tricks.
The generally used solution is to
always provide an alternate form of
vararg functions, so printf has
vprintf which takes a va_list in place
of the .... The ... versions are just
wrappers around the va_list versions.
This is exactly what I was looking for. I performed a test implementation like this:
void Error(const char* format, ...)
{
char dest[1024 * 16];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
printf(dest);
}
You are looking for variadic functions. printf() and sprintf() are variadic functions - they can accept a variable number of arguments.
This entails basically these steps:
The first parameter must give some indication of the number of parameters that follow. So in printf(), the "format" parameter gives this indication - if you have 5 format specifiers, then it will look for 5 more arguments (for a total of 6 arguments.) The first argument could be an integer (eg "myfunction(3, a, b, c)" where "3" signifies "3 arguments)
Then loop through and retrieve each successive argument, using the va_start() etc. functions.
There are plenty of tutorials on how to do this - good luck!
Simple example below. Note you should pass in a larger buffer, and test to see if the buffer was large enough or not
void Log(LPCWSTR pFormat, ...)
{
va_list pArg;
va_start(pArg, pFormat);
char buf[1000];
int len = _vsntprintf(buf, 1000, pFormat, pArg);
va_end(pArg);
//do something with buf
}
Using functions with the ellipses is not very safe. If performance is not critical for log function consider using operator overloading as in boost::format. You could write something like this:
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
class formatted_log_t {
public:
formatted_log_t(const char* msg ) : fmt(msg) {}
~formatted_log_t() { cout << fmt << endl; }
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
boost::format fmt;
};
formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }
// use
int main ()
{
log("hello %s in %d-th time") % "world" % 10000000;
return 0;
}
The following sample demonstrates possible errors with ellipses:
int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.
Have a look at the example http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, they pass the number of arguments to the method but you can ommit that and modify the code appropriately (see the example).

va_copy -- porting to visual C++?

A previous question showed a nice way of printing to a string. The answer involved va_copy:
std::string format (const char *fmt, ...);
{
va_list ap;
va_start (ap, fmt);
std::string buf = vformat (fmt, ap);
va_end (ap);
return buf;
}
std::string vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time.
s ize_t size = 1024;
char buf[size];
// Try to vsnprintf into our buffer.
va_list apcopy;
va_copy (apcopy, ap);
int needed = vsnprintf (&buf[0], size, fmt, ap);
if (needed <= size) {
// It fit fine the first time, we're done.
return std::string (&buf[0]);
} else {
// vsnprintf reported that it wanted to write more characters
// than we allotted. So do a malloc of the right size and try again.
// This doesn't happen very often if we chose our initial size
// well.
std::vector <char> buf;
size = needed;
buf.resize (size);
needed = vsnprintf (&buf[0], size, fmt, apcopy);
return std::string (&buf[0]);
}
}
The problem I'm having is that the above code doesn't port to Visual C++ because it doesn't provide va_copy (or even __va_copy). So, does anyone know how to safely port the above code? Presumably, I need to do a va_copy copy because vsnprintf destructively modifies the passed va_list.
You should be able to get away with just doing a regular assignment:
va_list apcopy = ap;
It's technically non-portable and undefined behavior, but it will work with most compilers and architectures. In the x86 calling convention, va_lists are just pointers into the stack and are safe to copy.
For Windows, you can simply define va_copy yourself:
#define va_copy(dest, src) (dest = src)
One thing you can do is if you do not otherwise need the vformat() function, move its implementation into the format() function (untested):
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <string>
#include <vector>
std::string format(const char *fmt, ...)
{
va_list ap;
enum {size = 1024};
// if you want a buffer on the stack for the 99% of the time case
// for efficiency or whatever), I suggest something like
// STLSoft's auto_buffer<> template.
//
// http://www.synesis.com.au/software/stlsoft/doc-1.9/classstlsoft_1_1auto__buffer.html
//
std::vector<char> buf( size);
//
// where you get a proper vsnprintf() for MSVC is another problem
// maybe look at http://www.jhweiss.de/software/snprintf.html
//
// note that vsnprintf() might use the passed ap with the
// va_arg() macro. This would invalidate ap here, so we
// we va_end() it here, and have to redo the va_start()
// if we want to use it again. From the C standard:
//
// The object ap may be passed as an argument to
// another function; if that function invokes the
// va_arg macro with parameter ap, the value of ap
// in the calling function is indeterminate and
// shall be passed to the va_end macro prior to
// any further reference to ap.
//
// Thanks to Rob Kennedy for pointing that out.
//
va_start (ap, fmt);
int needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
va_end( ap);
if (needed >= size) {
// vsnprintf reported that it wanted to write more characters
// than we allotted. So do a malloc of the right size and try again.
// This doesn't happen very often if we chose our initial size
// well.
buf.resize( needed + 1);
va_start (ap, fmt);
needed = vsnprintf (&buf[0], buf.size(), fmt, ap);
va_end( ap);
assert( needed < buf.size());
}
return std::string( &buf[0]);
}
va_copy() is directly supported starting in Visual Studio 2013. So if you can rely on that being available, you don't need to do anything.