Передача слишком большого количества аргументов в printf

Для других людей, занимающихся этим направлением. Существует неплохая запись в блоге и ссылка на библиотеку , которая предлагает Flask-SQLAlchemy как преимущества, без прямого связывания SQLAlchemy с Flask.

Однако слово предупреждения; Я пытался использовать Alchy, но все еще не мог понять, как интегрировать его в Flask и не-web-приложение, поэтому я пошел с принятым ответом давидизма на этот вопрос. Ваш пробег может отличаться.

30
задан JSBձոգչ 26 August 2010 в 19:56
поделиться

5 ответов

Вы, вероятно, знаете, что прототип функции printf выглядит примерно так

int printf(const char *format, ...);

Более полной версией этого может быть

int __cdecl printf(const char *format, ...);

__cdecl определяет "соглашение о вызовах", которое, наряду с другими вещи, описывает, как обрабатываются аргументы. В данном случае это означает, что аргументы помещаются в стек и стек очищается функцией, выполняющей вызов.

Одной из альтернатив _cdecl является __stdcall, есть и другие. С __stdcall соглашение заключается в том, что аргументы помещаются в стек и очищаются вызываемой функцией. Однако, насколько мне известно, функция __stdcall не может принимать переменное количество аргументов. Это имеет смысл, поскольку он не будет знать, сколько стека нужно очистить.

Если кратко, то в случае с функциями __cdecl безопасно передавать столько аргументов, сколько вы хотите, поскольку очистка выполняется в коде, выполняющем вызов. Если вы каким-то образом передадите слишком много аргументов функции __stdcall, это приведет к повреждению стека. Одним из примеров того, где это может произойти, является неправильный прототип.

Дополнительную информацию о соглашениях о вызовах можно найти в Википедии здесь.

15
ответ дан 27 November 2019 в 22:21
поделиться

Все аргументы будут помещены в стек и удалены, если фрейм стека удален. это поведение не зависит от конкретного процессора. (Помню только мейнфрейм без стека, разработанный в 70-х) Так что да, второй пример не подведёт.

3
ответ дан 27 November 2019 в 22:21
поделиться

printf предназначен для приема любого количества аргументов. Затем printf считывает спецификатор формата (первый аргумент) и при необходимости извлекает аргументы из списка аргументов. Вот почему слишком мало аргументов дает сбой: код просто начинает использовать несуществующие аргументы, обращаться к несуществующей памяти или что-то еще плохое. Но при слишком большом количестве аргументов лишние аргументы будут просто проигнорированы. Спецификатор формата будет использовать меньше аргументов, чем было передано.

3
ответ дан 27 November 2019 в 22:21
поделиться

Онлайн-проект стандарта C (n1256) , раздел 7.19.6.1, параграф 2:

Функция fprintf записывает вывод в поток, на который указывает stream, под управлением строки указывается форматом, который указывает, как последующие аргументы преобразованы для вывода. Если для формата недостаточно аргументов, поведение неопределенный. Если формат исчерпан, а аргументы остались, лишние аргументы оцениваются (как всегда), но в противном случае игнорируются. Функция fprintf возвращает значение, когда встречается конец строки формата.

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

33
ответ дан 27 November 2019 в 22:21
поделиться

Комментарий: и gcc, и clang выдают предупреждения:

$ clang main.c 
main.c:4:29: warning: more '%' conversions than data arguments [-Wformat]
  printf("Gonna %s and %s, %s!", "crash", "burn");
                           ~^
main.c:5:47: warning: data argument not used by format string 
                      [-Wformat-extra-args]
  printf("Gonna %s and %s!", "crash", "burn", "dude");
         ~~~~~~~~~~~~~~~~~~                   ^
2 warnings generated.
-2
ответ дан 27 November 2019 в 22:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: