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 开发者_如何学Cformat 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.
精彩评论