tags:

views:

135

answers:

6
+1  Q: 

vsnprintf and gcc

Hello,

I have the fallowing statement:

vsnprintf(target, size - 1, "%ls_%ls", str16_1, str16_2);

Do you know why this fails 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!

A: 

Use snprintf.

Matt Joiner
I have same result with snprintf function, an empty string
Felics
+2  A: 

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...

  1. Making wrappers around printf style functions
  2. Variadic macros are not an option

Otherwise just use *printf

Joe D
The function is a around printf style function. It is used inside a wide char string class.
Felics
@Felics: The fundamental problem that Joe D is pointing out is that you are passing the wrong arguments. You are passing what appears to be two strings (of some form or another) rather than a va_list.
David Thornley
+1  A: 

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).

Greg Hewgill
I found that is a mistake an corrected it, but I have the empty string as a result anyway...First time I tried like you said and and I had an empty string and after that I changed format with new_format...
Felics
A: 

What is your valist type? The correct type for variable list arguments is va_list with an underscore, no?

Jens Gustedt
typedef __darwin_va_list va_list;It was a typo mistake, I use va_list. I'm sorry, I'll correct that
Felics
A: 

Because I use this on Mac I found a work-around:

http://stackoverflow.com/questions/1420421/how-to-pass-on-a-variable-number-of-arguments-to-nsstrings-stringwithformat

It seems that vsnprintf can't handle 16 bits string. Maybe because wchar_t isn't 16 bits.

Felics
A: 

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
John Rocha
I use u16 as chars(unsigned shorts). These are used in a String class that is working on Windows/Visual Studio and I must port it on iPad. This was the only problem that I had with the class until now, but I found an work-around using NSString class.
Felics