2013-05-10 3 views
1

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

Когда функция вызывается, ей будут переданы дополнительные параметры, которые не являются частью объявления функции, но они находятся в конце списка параметров.

Я не могу определить, гарантировано ли это тем, как параметры функции передаются в C. Я предполагаю, что для выполнения переменных функций, таких как sprintf, это должно быть так, что предыдущие аргументы могут быть правильно решены, что находится на конце списка параметров?

Он, очевидно, отлично работает на нескольких платформах, но из любопытства я хотел бы знать, как и почему он работает.

+0

Это будет зависеть от вашего соглашения о вызове. Для cdecl это может быть неважно, но для чего-то вроде stdcall вы столкнетесь с проблемами. –

+0

Можете ли вы показать, что представляет собой объявление указателя функции в таблице и фактическое объявление вызываемой функции? – ouah

ответ

2

Ваши функции должны обязательно использовать соглашение о вызове cdecl (http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). Это вызывает аргументы в стеке в обратном порядке справа налево, гарантируя, что последний аргумент может быть легко расположен (верхняя часть стека) и используется для интерпретации остатка, например строки формата printf. Ответственность за очистку стека также несет абонент, который немного менее компактен, чем сама функция (как в случае с соглашением pascal/stdcall), но гарантирует, что списки переменных аргументов могут использоваться, и подразумевает, что конечные аргументы могут быть игнорируются.

+0

cdecl - это не единственное, что будет работать, практически любое соглашение о вызове для звонящего звонящего тоже будет очень хорошо работать. –

+1

Да, но поскольку это вопрос «c», скорее всего, cdecl. –

+0

Вы можете иметь списки переменных аргументов в соглашениях pascal/stdcall. У вас просто нетривиальное определение 'va_end'. Возможно, это не сработает, если вы не получите правильное количество аргументов. –

2

Но поскольку все задано до правильного типа функции, поскольку оно помещено в таблицу функций, никаких предупреждений не возникает.

Поэтому компилятор не может помочь. С программистов слишком много. > _ <

Я не могу определить, если это гарантировано, кстати параметры функции передаются в C. Я предполагаю делать VARIADIC функции как Sprintf, он должен быть так, что более ранние аргументы могут быть решены правильно что находится в конце списка параметров?

Технически у вас есть неопределенное поведение. Но для вашей платформы определено значение , чтобы использовать стандартные соглашения о вызовах C (см. Ответ Скотта) или что-то, что непосредственно сопоставляется с ними (обычно путем сопоставления первых N параметров с определенным набором регистров процессора).

Это очень много с переменными списками аргументов. Например, printf объявлен что-то вроде:

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

И его определение обычно используется система stdarg для обработки дополнительных аргументов, который выглядит как:

#include <stdarg.h> 

int printf(const char* format, ...) 
{ 
    va_list ap; 
    int result; 
    va_start(ap, format); 
    result = vprintf(format, ap); 
    va_end(ap); 
    return result; 
} 

Если вы на платформе со стандартом C, что va_end(ap) макрос обычно превращается в ничего-ничего. В этом случае вы можете уйти с передачей дополнительных аргументов функции. Но на некоторых платформах требуется вызов va_end() для восстановления стека до прогнозируемого состояния (т.где было до звонка va_start); в этих случаях ваши функции не оставят стек так, как он его нашел (он не будет выставлять достаточные аргументы из стека), поэтому ваша вызывающая функция может, например, сбой при выходе, когда он получает фиктивное значение для возврата адрес.

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