sscanf, переносящий функцию для усовершенствования указатель строки в C

У меня есть функция, которая делает серию вызовов к 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 параметр на конец аргумента перечисляет непосредственно или иначе внутри newSscanf(). Там некоторый путь состоит в том, чтобы работать вокруг этого или является мной точно также от обработки бухгалтерии вручную в каждом вызове?

7
задан Dusty 24 July 2010 в 02:37
поделиться

3 ответа

Вы правы - вы не можете запихнуть дополнительные параметры в 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);})
3
ответ дан 7 December 2019 в 14:30
поделиться

Вы вызываете функцию неправильно, посмотрите на параметр для char ** str , который подразумевает параметр вызова по ссылке:

if(newSscanf(&str, "%d", &fooInt) != 1)
{ 
   // error handling
}
0
ответ дан 7 December 2019 в 14:30
поделиться

Если не выяснить, как скрытые списки работают (и, следовательно, сделать ваш код непереносимым), невозможно изменить аргументы.

Но у меня была одна мысль, которая может сработать, а может и не сработать. Я не тестировал его, так как я действительно не думаю, что вам следует его использовать, но, если вы одержимы этим, это может помочь.

Поскольку вы просто хотите получить количество просканированных символов, вы должны понимать, что вы не должны делать это одновременно с фактической установкой переменных вызывающей стороны.

Пусть ваш код просканирует строку, чтобы установить аргументы, необходимые вызывающему. Никаких изменений там вообще не нужно.

Следующий этап немного сложнее.

Подсчитайте количество символов % в строке формата, за которыми сразу не следует % или * - другими словами, количество переменных. которые необходимо передать в 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;
}

Мне было бы интересно услышать, как это происходит, если вы решите попробовать. Это моя работа (и ответственность) сделано.Я счастлив продать вам бензопилу, но если вы отрубите ногу во время ее использования, это ваша проблема: -)

1
ответ дан 7 December 2019 в 14:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: