Действительно ли va_list переносимый?
В документации от Microsoft заявлено, что va_list, va_start, va_arg, va_end являются переносимыми макросами, однако не понятно, как это может быть реализовано, если параметры функции во многих архитектурах передаются в первую очередь через регистры, а затем через стек. Получается, реализация этих макросов должна контролировать как используемое ABI, так и соглашение о вызовах. Если первое явно задаётся компилятором, то используемое соглашение о вызовах определить внутри функции, вроде бы, невозможно.
Даже если это и можно определить, то как на уровне языка C получить доступ к регистрам, содержащим параметры?
Также сказано:
If
prev_paramis declared with theregisterstorage class, the macro's behavior is undefined.
Эту формулировку не понимаю. Насколько мне известно, объявлять функции таким образом не допускается - иначе мы предписываем компилятору нарушить соглашение о вызовах:
int func(register int first, ...);
Если же имелось в виду следующее
int func(int first, ...);
int main()
{
register int a = 3;
func(1, a);
}
то разве значение 3 из переменной a не переместится туда, куда предусмотрено соглашением о вызовах?
Ответы (2 шт):
Вопрос задан неверно.
Не "в документации от MS", и не "переносимость", а - СТАНДАРТ.
А уж как разработчики того или иного компилятора его реализуют - это их, разработчиков, проблемы.
Что касается register - это слово из лексикона С++ исключено :)
Всё просто: параметры в функции с переменным количеством аргументов всегда передаются через блоки памяти, это единственный способ не быть ограниченным в количестве таких параметров сверху количеством доступных регистров, используемых для передачи параметров в обычные функции. Блоки памяти могут быть аллоцированы на стеке (наиболее распространённый вариант), но ничто не мешает откусить память в куче или вообще организовать передачу параметров в виде списка или любого другого упорядоченного контейнера.
Функции с переменным количеством аргументов - зло и источник боли.