Как использовать 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++, и я далее гарантировал, что он работает с несколькими компиляторами, которые я могу найти.