2009-02-25 2 views
46

va_end - Макросъемка arg_ptr.Что такое va_end? Всегда ли нужно называть это?

После получения доступа список переменных аргументов, то arg_ptr указатель обычно сбрасывается va_end(). Я понимаю, что это требуется, если вы хотите переименовать список, но действительно ли это необходимо, если вы этого не сделаете? Это просто хорошая практика, как правило "всегда есть default: в вашем switch"?

+1

Это действительно хороший вопрос. Я хочу, чтобы кто-то ответил на это, описав архитектуру, где va_end не является no-op. – erikkallen

+1

FYI: MSVS2008 - #define _crt_va_end (ap) (ap = (va_list) 0) – Yarik

+0

@erikkallen: выполните поиск по Google для «define va_end», и вы найдете довольно необычные определения, которые могут или не могут быть по существу не- соч. – PlasmaHH

ответ

40

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, что может быть интересно, но при написании переносного кода вы должны рассматривать их как непрозрачные операции.

+0

Означает ли это, что указатель является «глобальным», и когда функция вызывается во второй раз без сброса указателя, стек будет поврежден? – Yarik

+3

Это может быть повреждено, потому что * вы не знаете, что делает va_start(). * Это может быть что угодно. И его нужно очистить. Поэтому, когда вы вызываете va_start(), вы * ДОЛЖНЫ * соответствовать ему с помощью va_end(). – greyfade

+0

Благодарим вас за разъяснения. – Yarik

10

В общей реализации «параметров, переданных в стек», я считаю, что va_end() обычно ничего/пусто/null. Однако на платформах, которые имеют менее традиционные схемы, это становится необходимым. Это «хорошая практика», чтобы включить его в нейтральную платформу.

+0

Он может сбросить стек в случае, если вы не перебирали все var_args. – Spidey

11

В Linux x86-64 только один обход можно выполнить через переменную va_list. Чтобы сделать больше обходов, его необходимо скопировать, используя va_copy. man va_copy объясняет деталь:

va_copy()

Очевидной реализации будет иметь va_list быть указателем на стека кадр VARIADIC функции.В такой установке (на сегодняшний день наиболее общий) не кажется, ничего против присвоения

va_list aq = ap; 

К сожалению, существуют также системы, которые делают это массив указателей (длины 1), и там нужно

va_list aq; 
    *aq = *ap; 

Наконец, в системах, где аргументы передаются в регистрах, может быть необходимо для va_start() для выделения памяти, хранить аргументы там, , а также указание по какой аргумент находится рядом, так что va_arg () может шаг через список. Теперь va_end() может снова освободить выделенную память . Чтобы разместить эту ситуацию, C99 добавляет макрос va_copy(), так , что выше назначение может быть заменен

va_list aq; 
    va_copy(aq, ap); 
    ... 
    va_end(aq); 

Каждый вызов va_copy() должен быть подкреплен соответствующей invoca- ции va_end() в той же функции. Некоторые системы, которые не поставляют va_copy(), вместо этого имеют __va_copy, поскольку это имя было использовано в проекте проекта .

+2

Чтобы это сделать; ничего особенного для Linux x86-64. 'va_copy' требуется, если вы хотите повторять дважды по списку, когда доступна только переменная' va_list'. (например, внутри функции, принимающей 'va_list' в качестве аргумента). Вы всегда можете вызывать 'va_start' и' va_end' столько, сколько хотите. –

+0

@MattMcNabb В x86-64 'va_list' поддерживает состояние обхода. На x86 это не так. –

+0

@downvoter, что не так? –

Смежные вопросы