Я хотел бы написать такую же процедуру, как 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
Ответ 1
Различные компиляторы могут реализовать эту функцию по-разному. В GCC он реализуется через спецификатор __attribute__
с атрибутом format
(читайте об этом здесь). Причина, по которой компилятор выполняет проверку, заключается только в том, что в стандартных файлах заголовков, поставляемых с GCC, функция printf
объявляется с помощью __attribute__((format(printf, 1, 2)))
Точно так же вы можете использовать атрибут format
, чтобы расширить те же функции проверки формата на свои собственные вариационные функции, которые используют те же спецификаторы формата, что и printf
.
Все это будет работать только в том случае, если соглашение о передаче параметров и используемые вами спецификаторы формата совпадают с стандартными функциями printf
и scanf
. Проверки жестко закодированы в компилятор. Если вы используете другое соглашение для передачи вариационных аргументов, компилятор не поможет вам его проверить.
Ответ 2
Это поведение сильно зависит от компилятора. Я считаю, что gcc предоставляет интерфейс для проверки типов переменных varical.
Ответ 3
printf()
и друзья не являются особенными, потому что они принимают переменное количество аргументов: пользовательские функции могут принимать переменное количество аргументов. Они являются особенными, потому что их поведение определяется стандартом, поэтому компилятор знает, какая корреляция должна быть между строкой формата и аргументами, переданными функции.
Фактически, компилятор знает, сколько аргументов передается функции при ее вызове, поэтому он анализирует строку формата и сравнивает ожидаемое число и типы аргументов с тем, какие аргументы фактически переданы функции, и выдает предупреждение, если они не соответствуют.
Если вы используете С++, я бы не стал писать собственные вариационные функции; есть несколько веских причин использовать их в большинстве проектов. Например, если вы делаете форматирование, используйте потоки или библиотеку, например Boost Format. Любая проблема, которая может быть решена с помощью вариационной функции, может быть решена с использованием невариантной функции, и почти во всех случаях результат более изящный, идиоматический и безопасный для типов.
Ответ 4
Фактически printf
вообще не имеет встроенной безопасности во время компиляции. Просто случается, что некоторые более свежие компиляторы внедрили специальные проверки, учитывая, что они точно знают, что означает строка формата с точки зрения дополнительных параметров. Когда вы используете ...
в качестве параметра, вы говорите, что хотите принять произвольные аргументы и нести полную ответственность за то, чтобы убедиться, что они верны. Компилятор не может проверить их для безопасности count/type.
Вместо того, чтобы пытаться заставить компилятор помочь вам таким образом, попробуйте использовать подход, используемый стандартными потоками. Используйте функцию (или шаблон), которая возвращает ссылку на this
, чтобы разрешить цепочку. Затем компилятор сможет сразу сказать вам, когда аргументы не соответствуют ожидаемому/поддерживаемому.
Ответ 5
В то время как кто-то отправил строку mpl:: string в группы boost. Я думаю, что это действительно могло попасть в библиотеку. Если это так, вы можете реализовать что-то вроде этого, предоставив строку шаблона в качестве параметра шаблона (mpl:: string), а затем используя некоторые довольно глубокие навыки метапрограммирования для анализа в нем битов форматирования. Затем вы будете использовать эту информацию, чтобы выбрать реализацию, которая имеет соответствующие аргументы count и типы.
Нет, я не собираюсь делать это за вас: P Это было бы довольно сложно. Однако я считаю, что это возможно.