Page 1 of 1

variadic function, VARARGS68K and va_list parameter

Posted: Thu Jan 23, 2014 11:17 am
by abalaban
I'm still puzzled by the need to use the VARARGS68K macro.
At first I thought it was only required to be used in the event we need to have/call 68k compatible API.
But in the end it seems that any variadic function requires this tag, especially if it tries to pass the va_list to another function.
However sometimes it does not help, can somebody clarify that?

The code I'm trying to get working is the following:

Code: Select all

std::string vstrprintf(const char * fmt, va_list ap)
{
  char buf[512];
  vsnprintf(buf, sizeof(buf), fmt, ap);
  buf[sizeof(buf)-1] = 0;
  return buf;
}

VARARGS68K std::string strprintf(const char * fmt, ...)
{
  va_list ap; va_start(ap, fmt);
  std::string str = vstrprintf(fmt, ap);
  va_end(ap);
  return str;
}
The resulting binary crashes in newlib due to the call to vsnprintf() from vstrprintf() itself called from strprintf().

Re: variadic function, VARARGS68K and va_list parameter

Posted: Thu Jan 23, 2014 12:51 pm
by salass00
None of the <stdio.h> #?printf() use linear varargs calling convention so I don't know why you think you should use VARARGS68K there.

This is what I use in NTFS3G/Ext2FS to redirect calls to printf() to my own vkprintf() function:

Code: Select all

int printf(const char *fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	int retval = vkprintf(fmt, ap);
	va_end(ap);
	return retval;
}

Re: variadic function, VARARGS68K and va_list parameter

Posted: Thu Jan 23, 2014 1:26 pm
by colinw
char buf[512];
-> return buf;

'buf' is an auto variable, it disappears when you leave the function.

Re: variadic function, VARARGS68K and va_list parameter

Posted: Thu Jan 23, 2014 1:36 pm
by salass00
colinw wrote:char buf[512];
-> return buf;

'buf' is an auto variable, it disappears when you leave the function.
Also the return value from the function should be a std::string object and not just a pointer to a char array.

Re: variadic function, VARARGS68K and va_list parameter

Posted: Fri Jan 24, 2014 11:10 am
by abalaban
salass00 wrote:
colinw wrote:char buf[512];
-> return buf;

'buf' is an auto variable, it disappears when you leave the function.
Also the return value from the function should be a std::string object and not just a pointer to a char array.
Which it is: prototype of vstrprintf is

Code: Select all

std::string vstrprintf(const char * fmt, va_list ap)
As such it is automatically converted to std::string upon exit. Note that the std::string constructor copies the buffer, not just point to it, as such it should work.
It appears that my crash was due to something else: the caller of strprintf was doing a loop on a statically allocated array of structure. The problem was the initialization of this array that was done like one would do in C. While Initializer lists have been added to C++11 our current GCC does not seem to like them, adding a constructor to the structure and calling it instead of just passing the member values in braces solved the problem.

Nonetheless I'm still obligated to use the VARARGS68K macro for all my variadic functions else some integer gets wrongly displayed, it is probably an alignment problem, which is solved by the side-effect of declaring the function as a VARARGS68K :?:

Re: variadic function, VARARGS68K and va_list parameter

Posted: Fri Jan 24, 2014 5:04 pm
by salass00
abalaban wrote: As such it is automatically converted to std::string upon exit. Note that the std::string constructor copies the buffer, not just point to it, as such it should work.
Well if you are sure that it's automatically converted, I guess it's OK. If it was my code I would use an explicit conversion though and not rely on the compiler to do it for me, but then I don't write much C++ code.
Nonetheless I'm still obligated to use the VARARGS68K macro for all my variadic functions else some integer gets wrongly displayed, it is probably an alignment problem, which is solved by the side-effect of declaring the function as a VARARGS68K :?:
Did you recompile everything after removing VARARGS68K or did you still have some object files compiled with the old VARARGS68K prototype?

BTW this is how I implement my kprintf() in filesysbox.library/NTFS3G/Ext2FS and it is working perfectly there:

Code: Select all

#define GET_SYSBASE (*(struct ExecBase **)4)
#define GET_IEXEC ((struct ExecIFace *)GET_SYSBASE->MainInterface)

APTR debug_mutex;
static char debug_buffer[512];

int kprintf(const char *fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	int retval = vkprintf(fmt, ap);
	va_end(ap);
	return retval;
}

int vkprintf(const char *fmt, __VALIST args) {
	struct ExecIFace *IExec = GET_IEXEC;
	IExec->MutexObtain(debug_mutex);
	int retval = vsnprintf(debug_buffer, sizeof(debug_buffer), fmt, args);
	IExec->DebugPrintF("%s", debug_buffer);
	IExec->MutexRelease(debug_mutex);
	return retval;
}
If it didn't write numbers correctly I wouldn't have gotten very far with any of these projects ;-).