Как использовать define внутри строки формата?
скажем у меня есть массив символов:
#define LEN 10
char arr[LEN + 1];
позволяет сделать некоторые операции scanf к нему:
scanf("Name: %s", arr);
это может быть опасно, если кто-то вводит имя длиной более 10 символов. Поэтому лучше использовать это:
scanf("Name: %10s", arr);
Ну, теперь у меня будут проблемы, если LEN
изменяется. Мне пришлось бы пройти весь код, чтобы исправить каждую строку, где я использовал 10
в контексте arr
. Поэтому я подумал о чем-то вроде это:
scanf("Name: %LENs", arr);
но это не сработает.LEN
не разрешается препроцессором, поскольку он используется внутри строки.
как использовать define внутри строки формата?
2 ответов
C присоединяется к соседним строковым литералам, и вы можете stringify параметр препроцессора с #
, поэтому следующее должно сделать трюк:
#define LEN 10
// this converts to string
#define STR_(X) #X
// this makes sure the argument is expanded before converting to string
#define STR(X) STR_(X)
[...]
scanf("Name: %" STR(LEN) "s", arr);
макросы необходимы, потому что только с #LEN
, ты LEN
расширено до 10, и только с одним макросом применения #
к его аргументу, результат будет "LEN"
(аргумент не будет развернут).
препроцессор / компилятор преобразует это в следующее шаги:
1. scanf("Name: %" STR_(10) "s", arr);
2. scanf("Name: %" "10" "s", arr);
3. scanf("Name: %10s", arr);
в последнем шаге, строковые литералы объединяются в один.
на боковой ноте, ваш scanf()
строка формата потребует от пользователя буквально ввести
Name: xyz
на самом деле матч. Сомневаюсь, что ты этого хотела. Вы, вероятно, хотите что-то вроде этого:
fputs("Name: ", stdout);
fflush(stdout);
scanf("%" STR(LEN) "s", arr);
также не следует использовать scanf()
на всех. Например,fgets()
, вся эта препроцессорная магия устарела. По причинам, почему ты не следует использовать scanf()
посмотреть мои руководство для начинающих от scanf()
.
ссылки: добавление кавычек в аргумент в препроцессоре C++
используйте этот трюк с одним хэшем:
#define STRINGIFY(a) #a
#define STRING(a) STRINGIFY(a)
scanf("Name: %" STRING(LEN) "s\n", name);
теперь вы можете stringify прямые токены препроцессора, такие как STRING(LEN)
.
и автоматически сцепляет примыкает строковые литералы, так что эти два essestially идентичны:
"Name: %10s\n"
"Name: %" "10" "s\n" // This one will be auto concatenated
препроцессор сначала заменяет STRING(LEN)
С "10"
, затем во время фактической компиляции, все те струны соединяются, Вот чего ты хочешь.
ссылка должна отображаться в первых нескольких результатах, если вы ищете в Google
c #определить двойные кавычки
в любом случае, показатели препроцессора не сильно отличаются между C и C++, и я далее гарантировал, что он работает с несколькими компиляторами, которые я могу найти.