8

一連の呼び出しをsscanf()行い、その後、文字列ポインターを更新して、次のsscanf()ように消費されていない最初の文字を指す関数があります。

if(sscanf(str, "%d%n", &fooInt, &length) != 1)
{ 
   // error handling
}
str+=length;

これをクリーンアップし、これを何度も複製しないようにするために、これを次のような便利なユーティリティ関数にカプセル化したいと思います。

int newSscanf ( char ** str, const char * format, ...)
{
  int rv;
  int length;
  char buf[MAX_LENGTH];
  va_list args;

  strcpy(buf, format);
  strcat(buf, "%n");
  va_start(args, format);
  rv = vsscanf(*str, buf, args, &length);  //Not valid but this is the spirit
  va_end(args);
  *str += length;

  return rv;
}

次に、追加のパラメーター/簿記を削除するために、以下のように呼び出しを簡素化できます。

if(newSscanf(&str, "%d", &fooInt) != 1)
{ 
   // error handling
}

残念ながら、&lengthパラメーターを arg リストの末尾に直接追加する方法、または .xml 内に追加する方法が見つかりませんnewSscanf()。これを回避する方法はありますか、それとも、呼び出しごとに手作業で簿記を処理するのと同じくらいうまくいきますか?

4

3 に答える 3

4

その通りです。余分なパラメータを .xml に詰め込むことはできませんva_list。あなたができる最善のことは、おそらく次のようなマクロトリックです。

int _newSscanf ( char ** str, int *length, const char * format, ...)
{
  int rv;
  va_list args;

  va_start(args, format);
  rv = vsscanf(*str, format, args);
  va_end(args);
  *str += *length;

  return rv;
}

#define NEW_SSCANF_INIT int _ss_len
#define newSscanf(str, fmt, ...) _newSscanf(str, &_ss_len, fmt "%n", __VA_ARGS__, &_ss_len)

...そして呼び出し元に次のことを要求します:

NEW_SSCANF_INIT;

if (newSscanf(&str, "%d", &fooInt) != 1)
{ 
   // error handling
}

GCC 拡張機能を使用できる場合は、「ステートメント式」を使用してそのNEW_SSCANF_INIT部分を削除し、よりクリーンにすることができます。

#define newSscanf(str, fmt, ...) ({int _ss_len; _newSscanf(str, &_ss_len, fmt "%n", __VA_ARGS__, &_ss_len);})
于 2010-03-17T01:08:28.970 に答える
1

可変長リストが内部でどのように機能するか (したがって、コードを移植不可能にする) を理解する以外に、引数を変更する方法はありません。

しかし、うまくいくかもしれないしうまくいかないかもしれないという考えが1つありました。私はあなたがそれを使うべきではないと本当に思っているので、私はそれをテストしていませんが、もしあなたがこれをすることに夢中になっているなら、それは役立つかもしれません.

スキャンされた文字数を取得したいだけなので、呼び出し元の変数の実際の設定と同時にそれを行う必要はないことに注意してください。

コードで文字列をスキャンして、呼び出し元の必要に応じて引数を設定します。そこにはまったく変更は必要ありません。

次の段階は少しトリッキーな段階です。

or -%がすぐ後に続かないフォーマット文字列の文字数を数えます。つまり、. これが上限より大きいかどうかをアサートします (以下のコードを参照)。%*sscanf

次に%n、フォーマット文字列の末尾にシーケンスを追加して、文字数を取得できるようにします。

次に、新しいフォーマット文字列を使用して、ジャンク バッファーを (繰り返し) 使用して、最後の値 (文字数) を含むスキャンからすべての値を受け取ります。

このようなもの(デバッグの責任はあなたにあります):

typedef union {
    char junk[512]; // Be *very* careful with "%s" buffer overflows.
    int length;
} tJunkbuff;

int newSscanf (char **str, const char *format, ...) {
    int rv, length;
    char buf[MAX_LENGTH];
    tJunkBuff junkbuff;
    va_list args;

    // Populate variables.

    va_start (args, format);
    rv = vsscanf (*str, buf, args);
    va_end (args);

    // Get length.

    // String scanning for % count and assert/error left out.
    // Only 20 allowed (depends on number of jb.junk variables below (n-1)).
    strcpy (buf, format);
    strcat (buf, "%n");
    sscanf (*str, buf,
        jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
        jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
        jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
        jb.junk,jb.junk, jb.junk, jb.junk, jb.junk,
        jb.junk); // May need to be "&(jb.junk)" ?
    *str += jb.length;

    return rv;
}

やってみようと思ったら、どうなるか聞いてみたいです。これで私の仕事 (および責任) は完了です。喜んでチェーンソーをお売りしますが、使用中に足を切ってしまったら、それはあなたの問題です :-)

于 2010-03-17T00:21:03.593 に答える
0

関数を間違って呼び出していchar **strます。参照渡しパラメーターを意味するパラメーターを見てください。

if(newSscanf(&str, "%d", &fooInt) != 1)
{
   // エラー処理
}
于 2010-03-17T00:21:42.450 に答える