Click here to Skip to main content
15,907,906 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
C language function printf has a very different parameter which is ..., something like this below:
C++
int printf(const char *format, ...);

It's something about var_list dealing with var_args. I have a similar function for recording log informations.
C++
void LOG(const char* format,...) {
    va_list list;
    time_t t=time(NULL);
    tm* tp=localtime(&t);
    char log_spin[256]="";
    char log_buffer[1024*4]="";
    
    if(format==NULL||!LOGFILE) return;
    
    sprintf(log_spin,"[%04d-%02d-%02d %02d:%02d:%02d]",
            tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,
            tp->tm_hour,tp->tm_min,tp->tm_sec);
    strcpy(log_buffer,log_spin);
    size_t occuppied=strlen(log_buffer);
    size_t remain=sizeof(log_buffer)-occuppied;
    int count=0;
    
    va_start(list,format);
    count=vsnprintf(&log_buffer[strlen(log_buffer)],remain,format,list);
    va_end(list);
    
    if(count>=remain) sprintf(&log_buffer[sizeof(log_buffer)-5],"...\n\0");
    else log_buffer[strlen(log_buffer)]='\n';
    
    fprintf(LOGFILE,log_buffer);
    fflush(LOGFILE);
}


This codes use the simiar function vsnprintf dealing with format and recording parameters. It worked well utill recording parameters contains some characters like %, which when I tried to log some url with muti-bytes characters, as you know not supported in URL, there would be some conversion by using % together with hex value like %2d%4f...
My URL may like this:
https://www.zhihu.com/search?hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1228623761%7D&hybrid_search_source=Entity&q=%E6%9D%8E%E7%8E%89%E6%B9%96&search_source=Entity&type=content
see, there is a lot characters including %.
But, when you pass the url to this LOG function , sh*t happened. When I try to debug it, exception occurried (MSVC). OK, I believe there is something wrong with my LOG codes. Did the standard C function "printf" support it? I try to print the same url on console, all OK! That means there is a proper way to deal with % character which I just don't know. There must be a standard answer for it.
So, This is my problem , how to deal with character % in va_list?

What I have tried:

To simplify my code , I paste the code and the test input here.
C++
int vsnprintf_test(char* format,...) {
    char buffer[256]={0};
    va_list list;
    int count=0;
    
    va_start(list,format);
    count=vsnprintf(buffer,sizeof(buffer),format,list);
    va_end(list);
    
    printf(buffer);
    
    return count;
}


the caller:
C++
char msg[256] = { 0 };//"";
msg[0] = '%'; //the character which caused the exception 
msg[1] = 'A';
printf("%s\n",msg); //all ok
vsnprintf_test(msg); // crashed.

I don't know how to fix this code. How did function printf do with character %?
Posted
Updated 23-Jan-23 23:35pm
v2

Look at the documentation: https://cplusplus.com/reference/cstdio/vsnprintf/[^] and you will see that the format is not the first parameter to vnsprintf - it's the third.
So the string you pass to printf in your tiny example is the data to print, but the format to print it with in your vnsprintf call: "%A" which is an unrecognised print format. Pass it "%s" instead, and it'll work.

So go back to your LOG function, and work out what you should be passing, and what you should be doing with it - because it's very unlikely that you want to pass a format to a "Log this" function - instead, you want to pass it data to actually log ...
 
Share this answer
 
Comments
Yount_0701 24-Jan-23 3:50am    
quote "%A" which is an unrecognised print format. Pass it "%s" instead, and it'll work.
you mean vsnprintf_test("%s",msg)? Do you ever try? Does it work ?
As far as I have done, apparently the output was not what we expected.
Hold on before go back to LOG function , because here on my msvc , the output was not "%A" even if I adjust the caller like "vsnprintf_test("%s",msg)",it's still something like "0X0.0000000000002P-1022" , nonsense as adjust before.
OriginalGriff 24-Jan-23 4:08am    
No, read what I said ...
Yount_0701 24-Jan-23 4:15am    
https://s2.loli.net/2023/01/24/XvzekrQgT4c853i.png
the pics show the result. forget about LOG function before the vsnprintf_test really works.
You said no confused me, could you plz show me your exact way by code?
OriginalGriff 24-Jan-23 4:49am    
Read what I said. Read the documentation.
Think about the code *you* wrote. What do you pass to the function, and why?
Yount_0701 24-Jan-23 5:09am    
I read your comment again, right now I'm not sure what you are talking about. I believe this is not a very deep or hard question. I try my best to show what am doing and what am expected. At last I show my code together with result pictures. I think you have already be clear about my stuck and my perpose. I believe there is an certain answer about it. Also I'm sure we could both make a progress by present coding on this topic.Otherwise, repeat reading don't make any sense. Thank you@OriginalGriff
C++
vsnprintf_test(msg);

Because you are missing the format string parameter in your call to vsnprintf_test. It should be:
C++
vsnprintf_test("%s\n", msg);
 
Share this answer
 
Comments
Yount_0701 24-Jan-23 4:10am    
As the comment before this, it's not work,that's my test on my MSVC environment. In case of cheap talk , I provide the pics here https://s2.loli.net/2023/01/24/XvzekrQgT4c853i.png
Richard MacCutchan 24-Jan-23 4:25am    
Yes, because the first call to vsnprintf_test is still incorrect:
vsnprintf_test(msg);

In this case vsnprintf_test will try to use msg as a format string. And when it sees the % character it will try to extract a parameter from the call stack. But since there are no parameters it will crash the program.
Yount_0701 24-Jan-23 4:43am    
https://sm.ms/image/3iQWTMkSCcFeNYa
The same story.
Yount_0701 24-Jan-23 4:31am    
https://sm.ms/image/3iQWTMkSCcFeNYa
Now what ? guys?
Richard MacCutchan 24-Jan-23 5:58am    
You still have the same issue in your vsnprintf_test function:
    count=vsnprintf(buffer,sizeof(buffer),format,list);
    va_end(list);
    
    printf(buffer); // buffer contains the string "%A", so printf needs a format string

So that printf statement should always be:
    printf("%s\n", buffer); // ensure that printf does not crash

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900