【解決方法】文字 % に関する Vnsprintf パラメータの問題

プログラミングQA


C言語関数 printf は非常に異なるパラメータを持っています。 、以下のようなもの:

C++
int printf(const char *format, ...);

これは、var_args を扱う var_list に関するものです。 ログ情報を記録するための同様の機能があります。

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);
}

このコードは、simiar 関数を使用します vsnprintf フォーマットと記録パラメータを扱います。 %2d% のような 16 進値と一緒に % を使用することで、いくつかの変換が行われます。 4f…
しかし、この LOG 関数に URL を渡すと、sh*t が発生しました。 デバッグしようとすると、例外が発生しました(MSVC)。 OK、LOG コードに問題があると思います。 Cの標準関数「printf」は対応していましたか? 同じ URL をコンソールに出力しようとしましたが、すべて OK です。 つまり、私が知らない % 文字を処理する適切な方法があるということです。 それに対する標準的な答えがあるはずです。
だから、これは私の問題です、va_list の文字 % をどう扱うか?

私が試したこと:

コードを簡素化するために、コードとテスト入力をここに貼り付けます。

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;
}

呼び出し側:

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.

このコードを修正する方法がわかりません。 関数printfは文字%をどのように処理しましたか?

解決策 1

ドキュメントを見てください: https://cplusplus.com/reference/cstdio/vsnprintf/[^] フォーマットが vnsprintf の最初のパラメータではなく、3 番目のパラメータであることがわかります。
したがって、小さな例で printf に渡す文字列は、印刷するデータですが、 vnsprintf 呼び出しでそれを印刷する形式は、認識されない印刷形式である “%A” です。 代わりに「%s」を渡すと、機能します。

LOG 関数に戻り、何を渡す必要があるか、何を行う必要があるかを検討します。「これをログに記録する」関数にフォーマットを渡すことはほとんどないため、代わりに、データを渡して実際にログに記録します…

コメント

タイトルとURLをコピーしました