forward argslist "..." from a c++ to c function - c++

forward argument list from a c++ class member function to a c function, (a wrapper I am creating)
not sure if it is correct? look in the comment inside argsPrinter
// c++ a class function
void argsPrinter( const char *format , ... ){
//markFile(&mApiObj, format , ...); how to pass forward the ... to the c function
/*
va_list args;
va_start (args, format);
markFile(&mApiObj, format , args);
va_end(args);
*/
}
// c function
void markFile(someCustomApi* a, const char *format , ...)
{
FILE *file= fopen(a->somePath, "a");
if(file)
{
va_list args;
va_start (args, format);
vfprintf(file, format, args);
va_end (args);
fclose(file);
}
//else do nothing
}
Edit
the implementation changed, however, I may consider implementing an aditional function, if forward is not allowed to the ...
as markFile(&mApiObj, format , ...);

You can't. If the library containing markFile doesn't provide a markFileV (similar to vsprintf being the counterpart to sprintf), it's just not possible to do this.
Given that you have the source of the C function, you may be able to change that, though.
On a side note (if you have any influence on the C code), this may be a reduced example, but why is markFile first formatting into a buffer (that is PATH_MAX chars long, of all things! What does that have to do with anything?) and then using fprintf to write out the results? Why not just use vfprintf directly?

It's not possible to forward C-style variadic arguments. That's why both fprintf and vfprintf exist. If you need to forward them, you'll have to create your own version of markFile, something like vmarkFile, which would accept a va_list instead of ....

How about just call your C++ function inside implementation of C function?
Such as your C++ function
void argsPrinter( const char *format , ... ){
//markFile(&mApiObj, format , ...); how to pass forward the ... to the c function
/*
va_list args;
va_start (args, format);
markFile(&mApiObj, format , args);
va_end(args);
*/
}
You can implement your C function by calling it:
void markFile(someCustomApi* a, const char *format , ...)
{
a->argsPrinter(format, ... );
//else do nothing
}

Since it is highly ABI dependent you can not do this easily.
Alternatively you can use libffi. Look for variadic function call in the man page.
I still recommend that you write a function that accept a va_list as parameter like vsprintf and co.

Related

Forward variadic function arguments to another variadic function without cost

I have a variadic function LogDebug for log writing. Logging happens in two modes.
My application forwards variadic arguments to another variadic function LogDebugEx in most cases hence that path needs to optimize.
To be specific it takes 38% for vsnprintf for some of my requests on callgrind graph. Please note that this function called many times for a single request.
void LogDebug(const char* zFormat, ...)
{
char zDesc[5000];
va_list ap;
va_start(ap, zFormat);
vsnprintf(zDesc, 5000, zFormat, ap); // Need to optimize in remode mode.
va_end(ap);
if (m_logMode == LOG_MODE_LOCAL) // Does not need to optimize this mode.
{
// This mode is not interested.
}
else // m_logMode == LOG_MODE_REMOTE, critical path
{
LogDebugEx("%s", zDesc); // Forwarded to new variadic function
}
}
Question : I need to avoid copying whole argument list to zDesc array before forwarding to LogDebugEx function.
Is there a way i can perfect forward variadic arguments coming to LogDebug into LogDebugEx function?
Any other fancy way to do this would also be fine without changing function calls to LogDebug.
I have C++11 supported compiler GCC 4.9.3.
If we have c++11, why mess around with variadic argument lists?
#include <utility>
extern enum {LOG_MODE_LOCAL, LOG_MODE_REMOTE} m_logMode;
extern void LogDebugEx(const char*, ...);
template<class...Args>
void LogDebug(const char* zFormat, Args&&...args)
{
if (m_logMode == LOG_MODE_LOCAL) // Does not need to optimize this mode.
{
char zDesc[5000];
snprintf(zDesc, 5000, zFormat, args...);
// do what you have to do here
}
else // m_logMode == LOG_MODE_REMOTE, critical path
{
LogDebugEx(zFormat, std::forward<Args>(args)...); // Forwarded to new variadic function
}
}

How to wrap variadic function with unknown types?

I have a function in a lib that takes a message and variadic parameters and print them like printf.
for e.g.:
printMe(const char *fmt,...);
I'm trying to wrap this function. I don't know what is the parameters types and count.
I've trying to do it like this:
printMeWrapper(const char *message,...)
{
va_list argptr;
va_start(argptr, message);
printMe( message,argptr);
va_end(argptr);
}
But this only prints the first argument. Any idea on how to do this correctly?
You have to create a second printMe function taking a va_list argument, just like there's printf and vprintf:
void printMeVa(const char *fmt, va_list va)
{
...
}
You could use a macro instead:
#define printMeWrapper(message, ...) \
DoSmthBefore(); \
printMe(message, __VA_ARGS__); \
DoSmthAfter();

How to pass variable argument parameter to another function?

Short version: How can I pass the contents represented by ... in a variable argument function to another function without first parsing it into a va_list?
Long version:
Below are two functions in a class of mine. I would like to draw your attention to the fact that the first four lines of each function are identical. And I have a half dozen other functions in this class with the same first four lines.
void cyclOps::Logger::warn(char* szFile, char* szFunction, int iLine, char* szFormat, ...) {
va_list vaArguments;
va_start(vaArguments, szFormat);
char szOutput[10000];
_vsnprintf_s(szOutput, CYCLOPSSIZEOF(szOutput), _TRUNCATE, szFormat, vaArguments);
this->log("WARNING: %s [%s - %s(%d)]", szOutput, szFile, szFunction, iLine);
}
void cyclOps::Logger::info(char* szFormat, ...) {
va_list vaArguments;
va_start(vaArguments, szFormat);
char szOutput[10000];
_vsnprintf_s(szOutput, CYCLOPSSIZEOF(szOutput), _TRUNCATE, szFormat, vaArguments);
this->log("INFO: %s", szOutput);
}
I would like to put these four identical lines in a single function called summarizeVariableArguments() and call it something like this...
void cyclOps::Logger::info(char* szFormat, ...) {
std::string strOutput = this->summarizeVariableArguments(/* TBD */);
this->log("INFO: %s", strOutput.c_str());
}
...where the contents of strOutput would be the same as the contents of szOutput in the two previous functions. But how do I pass the ... parameter to another function?
You cannot do that portably (or perhaps at compile time, with horrible C++2011 variadic template tricks).
If you want to call at runtime a variadic function, you may want to use the libffi.
Details are operating system, compiler, processor and ABI specific. (but libffi is trying to abstract them).
That's what perfect forwarding is all about + variadic templates.
template<typename ...Args>
void cyclOps::Logger::info(char* szFormat, Args &&...args) {
std::string strOutput = this->summarizeVariableArguments(std::forward<Args>(args)...);
this->log("INFO: %s", strOutput.c_str());
}
You make another function that accepts va_list to do the job like so:
void cyclOps::Logger::vLog(const char* format, va_list args)
{
std::string logMessage = vFormat<10000>(format, args);
// Do what you want with logMessage
}
template <size_t BufferSize>
std::string cyclOps::Logger::vFormat(const char* format, va_list args)
{
char buffer[BufferSize];
vsprintf(buffer, format, args);
return std::string(buffer);
}
I have tested this on MSVC and GCC for my project. All I can say is it works for me.
Here's a working example. This solution works for C++03 and I believe should work with C++11.

Can I return early from a variable-argument function?

Suppose I have two C++ functions for debug output:
void Trace( const wchar_t* format, ... )
{
va_list args;
va_start( args, format );
VarArgTrace( format, args );
va_end( args );
}
void VarArgTrace( const wchar_t* format, va_list args )
{
WCHAR buffer[1024];
//use ::_vsnwprintf_s to format the string
::OutputDebugStringW( buffer );
}
the above uses Win32 OutputDebugStringW(), but it doesn't really matter. Now I want to optimize the formatting so that when there's no debugger attached formatting is not done (I measured - speedup is significant):
void Trace( const wchar_t* format, ... )
{
if( !IsDebuggerPresent() ) {
return;
}
//proceed as previously
va_list args;
.....
}
will the fact that I return early once IsDebuggerPresent() returns null affect anything except that formatting will be skipped?
I mean I no longer call va_start and va_end - will this matter? Will skipping va_start and va_end cause any unexpected behavior changes?
No, there is no obligation to use va_start in a varargs function.
If you don't use va_start you cannot use va_end; if you use va_start you should use va_end, no matter how the function returns.
The only requirement on an early return is that if you have used (executed) va_start(), you must use va_end() before you return.
If you flout this rule, you'll get away with it on most systems, but some system somewhere needs the va_end(), so don't risk omitting it. It is undefined behaviour to omit it.
Other than that rule, it is up to you how you handle your return. Your proposed early return is not a problem.
All those macros do (on Windows at least) are pointer manipulation for a bookmark in the arg list. Returning early will be fine. This is compiler-specific, though I can't imagine why early return would be a problem on other platforms.
From x86 vadefs.h:
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
That's quite safe, because in C languages, the job of 'cleaning' the passed parameters from the stack is always done by the calling function, not the called one.
Some languages (Pascal springs to mind) may do this the other way round. This is potentially more efficient, but only works because there's no concept of a variable number of arguments.
There's not much overhead in the varargs stuff, usually just a few pointer manipulations.
There's probably slightly more overhead in setting up the stack to each varargs call, so instead of
void Trace( const wchar_t* format, ... )
{
if( !IsDebuggerPresent() ) {
return;
}
//proceed as previously
va_list args;
.....
}
you're probably better off using the preprocessor to prevent calls to trace stuff in non debug builds.
Littering your code with
if( IsDebuggerPresent() ) Trace( stuff... );
seems quite distateful too.
Did VC2010 get variadic macros yet? :)

How to pass variable number of arguments from one function to another?

Is there any way to directly pass a variable number of arguments from one function to another?
I'd like to achieve a minimal solution like the following:
int func1(string param1, ...){
int status = STATUS_1;
func2(status, param1, ...);
}
I know I can do this using something like the following, but this code is going to be duplicated multiple times so I'd like to keep it as minimalist as possible while also keeping the function call very short
int func1(string param1, ...){
int status = STATUS_1;
va_list args;
va_start(args, param1);
func2(status, param1, args);
va_end(args);
}
Thanks!
No, you have to pass the varargs using a va_list as per your second example.
It's just 3 lines extra code, if you want to avoid duplicating those lines, and func2 is always the same, or atleast takes the same parameters, make a macro out of it.
#define CALL_MY_VA_FUNC(func,param) do {\
va_list args; \
va_start(args,param);\
func(param,param,args);\
va_end(args); } while(0)
Just pass args as a parameter of type va_list to func2
Maybe you could try wrapping the parameters in a struct.
struct Params
{
int status;
std::string param1;
};
void func1(Params& params)
{
int status = params.status;
func2(params);
}
void func2(Params& params)
{
std::string param1 = params.param1;
}
I sometime use that trick when the list of parameter changes a lot during refactoring.
I'm not sure from your question if that could solve your problem though.
--
It is interesting to note that the same thing can be used for templates by defining typedefs and the like in the struct (i usually always use class in my code, since there is basically no difference between struct and class in c++) instead of normal members. It can be a workaround to the problem of having to maintain code with lot of templates that will change a lot during refactoring or developement.