va_end
предназначенный чистка. Вы не хотите разбивать стек, не так ли?
От man va_start
:
va_end()
Каждый вызов va_start() должны быть согласованы с соответствующим вызовом va_end() в одной и той же функции. После вызова va_end (ap) переменная ap не определена. Возможны множественные обходы списка, каждая из которых заключена в скобки с помощью va_start() и va_end(). va_end() может быть макросом или функцией.
Обратите внимание на наличие слова должно.
Стек может быть поврежден, потому что вы не знаете, что va_start()
делает. Макросы va_*
предназначены для обработки как черные ящики. Каждый компилятор на каждой платформе может делать все, что захочет. Он ничего не может сделать или может многое сделать.
Некоторые ABI передают первые несколько аргументов в регистрах, а остальные - в стеке. A va_arg()
может быть сложнее. Вы можете посмотреть, как данная реализация делает varargs, что может быть интересно, но при написании переносного кода вы должны рассматривать их как непрозрачные операции.
Это действительно хороший вопрос. Я хочу, чтобы кто-то ответил на это, описав архитектуру, где va_end не является no-op. – erikkallen
FYI: MSVS2008 - #define _crt_va_end (ap) (ap = (va_list) 0) – Yarik
@erikkallen: выполните поиск по Google для «define va_end», и вы найдете довольно необычные определения, которые могут или не могут быть по существу не- соч. – PlasmaHH