vsnprintf and gcc

2020-06-29 11:10发布

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!

标签: c++ c gcc printf
6条回答
太酷不给撩
2楼-- · 2020-06-29 11:26

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

查看更多
Fickle 薄情
3楼-- · 2020-06-29 11:28

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

查看更多
成全新的幸福
4楼-- · 2020-06-29 11:34

Use snprintf.

查看更多
放我归山
5楼-- · 2020-06-29 11:36

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

查看更多
冷血范
6楼-- · 2020-06-29 11:49

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
查看更多
老娘就宠你
7楼-- · 2020-06-29 11:51

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.

查看更多
登录 后发表回答