Как получить предупреждения или ошибки во время компиляции в стиле printf - PullRequest
10 голосов
/ 24 июня 2010

Я хотел бы написать подпрограмму наподобие printf, не функционально, а скорее, чтобы подпрограмма имела такие же характеристики проверки времени компиляции, что и printf.

Например, если у меня есть:

{
   int i;
   std::string s;
   printf("%d %d",i);
   printf("%d",s.c_str());
}

Компилятор жалуется так:

1 cc1plus: warnings being treated as errors
2 In function 'int main()':
3 Line 8: warning: too few arguments for format
4 Line 9: warning: format '%d' expects type 'int', but argument 2 has type 'const char*'

пример кода

Являются ли printf и co специальными функциями, которые компилятор обрабатывает по-другому илиЕсть какой-то трюк, чтобы заставить это работать на любой пользовательской функции?Конкретные компиляторы, которые меня интересуют: gcc и msvc

Ответы [ 5 ]

18 голосов
/ 24 июня 2010

Различные компиляторы могут реализовывать эту функцию по-разному.В GCC это реализовано через спецификатор __attribute__ с атрибутом format (читайте об этом здесь ).Причина, по которой компилятор выполняет проверку, заключается в том, что в стандартных заголовочных файлах, поставляемых с GCC, функция printf объявлена ​​с __attribute__((format(printf, 1, 2)))

Точно так же, как вы можете использовать атрибут format для расширенияте же функции проверки формата, что и в ваших собственных переменных функциях, которые используют те же спецификаторы формата, что и printf.

Все это будет работать только в том случае, если соглашение о передаче параметров и используемые вами спецификаторы формата совпадают сиспользуется стандартными функциями printf и scanf.Проверки жестко запрограммированы в компиляторе.Если вы используете другое соглашение для передачи переменных аргументов, компилятор не поможет вам проверить его.

5 голосов
/ 24 июня 2010

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

2 голосов
/ 24 июня 2010

printf() и друзья не являются особенными, потому что они принимают переменное число аргументов: пользовательские функции также могут принимать переменное количество аргументов. Они особенные, потому что их поведение определяется стандартом, поэтому компилятор знает, какая должна быть корреляция между строкой формата и аргументами, передаваемыми в функцию.

Фактически, компилятор знает, сколько аргументов передается функции, когда она вызывается, поэтому он анализирует строку формата и сравнивает ожидаемое число и типы аргументов с тем, какие аргументы фактически передаются в функцию, и выдает предупреждение, если они не совпадают.

Если вы используете C ++, я бы избегал написания ваших собственных функций с переменными числами; Есть несколько веских причин использовать их в большинстве проектов. Например, если вы выполняете форматирование, используйте потоки или библиотеку, например Boost Format . Любая проблема, которая может быть решена с помощью функции с переменными значениями, может быть решена с использованием функции без переменных величин, и почти во всех случаях результат является более элегантным, идиоматическим и безопасным для типов.

1 голос
/ 24 июня 2010

На самом деле printf вообще не имеет встроенной безопасности во время компиляции. Случается, что некоторые более поздние компиляторы реализовали специальные проверки, учитывая, что они точно знают, что означает строка формата с точки зрения дополнительных параметров. Когда вы используете ... в качестве параметра, вы говорите, что хотите принять произвольные аргументы и принять полную ответственность за то, чтобы убедиться, что они верны. Компилятор не может проверить их на безопасность подсчета / типа.

Вместо того чтобы пытаться заставить компилятор помочь вам в этом, попробуйте использовать подход, используемый стандартными потоками: используйте (возможно, шаблон) функцию или оператор, который возвращает ссылку на this, чтобы разрешить сцепление. Тогда компилятор сразу же сообщит вам, когда аргументы не соответствуют ожидаемым / поддерживаемым.

0 голосов
/ 24 июня 2010

Некоторое время назад кто-то опубликовал mpl :: string для групп поддержки.Я думаю, что это на самом деле попало в библиотеку.Если это так, вы можете реализовать что-то вроде этого, предоставив строку шаблона в качестве параметра шаблона (mpl :: string), а затем используя некоторые довольно глубокие навыки метапрограммирования для разбора битов форматирования в нем.Затем вы использовали бы эту информацию, чтобы выбрать реализацию с соответствующим количеством аргументов и типами.

Нет, я не собираюсь делать это за вас: P Это было бы довольно сложно.Однако я верю, что это было бы возможно.

...