Как передать спецификатор ширины переменной длины в sscanf?

sscanf(input_str, "%5s", buf); //reads at max 5 characters from input_str to buf

Но мне нужно использовать что-то вроде% MACRO_SIZE вместо% 5s

Тривиальное решение состоит в том, чтобы создать строку формата для того же

char fmt_str[100] = "";    
snprintf(fmt_str, 100, "%%%ds", MACRO_SIZE);
sscanf(input_str, fmt_str, buf);

Есть ли лучший способ добиться того же?

Ответ 1

если ваш MACRO_SIZE является const во время компиляции, вы можете попробовать следующее:

#define MACRO_SIZE "5"
snprintf(fmt_str, 100, "%" MACRO_SIZE "s", buf);

Ответ 2

Как сказал Стефан, но для sscanf() для более правильного ответа на вопрос и с немного более сложным макросом:

#define MACRO_SIZE 5

#define FORMAT(S) "%" #S "s"
#define RESOLVE(S) FORMAT(S)

char buf[MACRO_SIZE + 1];
sscanf(input_str, RESOLVE(MACRO_SIZE), buf);

Это использует автоматическое объединение C соседних строковых литералов, чтобы сформировать нужную строку форматирования во время компиляции. Это работает только в том случае, если MACRO_SIZE является макросом препроцессора, а не обычной переменной времени выполнения.

Дополнительный вызов макроса через RESOLVE() необходим, поскольку в противном случае аргумент не будет разрешен к его значению #define d, и мы получим строку форматирования "%MACRO_SIZEs", которая не является тем, что мы хотим.

Ответ 3

"Правильное" решение - это то, что вы называете тривиальным. Все эти умные макросы (я бы использовал m4 самостоятельно) просто сделают ваш код менее управляемым, если вы просто оставите его как константу.

Проблема, которую вы здесь имеете, это строки, которые не являются структурой данных первого класса в C. Они представляют собой массив байтов. Поэтому вам нужно построить массив, в котором вы хотите получить нужное значение, и вы создаете этот массив с помощью sprintf. Это некрасиво, но это правильно.

Если у вас проблемы с производительностью, и вы отследили ее здесь, то да, устраните вызовы функций. Но если значение MACRO_SIZE повторяется сто раз или распространяется на несколько файлов, я бы просто изменил литерал. Макрос просто притворяется с большей гибкостью, использование sprintf фактически дает вам гибкость.