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