2016-01-03 11 views
0

В $ 6.5.2.2.6 стандарт C11:Что означает это утверждение в стандарте C11 (о вариационных функциях)?

Если выражение, которое обозначает вызываемой функции имеет тип, который не включает в себя прототип, целые акции выполняются на каждый аргумент, и аргументы, имеют тип float, до double. Они называются рекламными акциями по умолчанию. Если число аргументов не равно числу параметров, то поведение не определено. Если функция определена с типом, в котором содержит прототип, и либо прототип заканчивается на эллипсис (, ...), либо типы аргументов после продвижения по службе не являются , совместимыми с типами параметров, поведение не определено. Если функция определена с типом, который не включает прототип, а типы аргументов после продвижения не совместимы с поведением параметров после продвижения по службе, то поведение не определено, за исключением следующих случаев:. ..

Что это значит - я действительно не могу это понять (особенно первая часть). Из того, что я могу, однако это означает, что определение функции, как это:

void func(int a, int b, ...) 
{ 
} 

А потом называть это не определено поведение, которое я думаю, что это глупо.

ответ

4

Ситуация выглядит следующим образом: Вы можете объявить функцию без списка параметров и вызвать эту функцию:

int main(void) 
{ 
    extern void f(); // no parameter list! 
    char c = 'x'; 
    f(c, 1UL, 3.5f); 
} 

В этой ситуации аргументы по умолчанию раскрученной: Первый аргумент способствует либо int или unsigned int (в зависимости от платформы), второй остается unsigned long, а третий повышается до double.

Когда программа связана, какая-то единица перевода должна содержать определение функции.Определение всегда содержит список параметров, даже если он пуст (но пустой список параметров в определении означает, что функция не принимает никаких параметров, в отличие от определения decl-that-not-a-definition выше, где это просто означает, что никакой информации не представлена ​​информация о параметрах):

void f(int, unsigned long, double) 
{ 
    // ... 
} 

standardese вы процитировали теперь говорите, что поведение не определенно, если типы параметров в данном определении не совместимы с рекламируемыми типами вызова, или если в списке параметров заканчивается многоточием.

Как следствие, отсюда следует, что если вы хотите использовать функцию с переменными аргументами (используя возможности <stdarg.h> для доступа аргументов), вы должны объявить функцию с прототипом:

extern void f(int, ...); // prototype (containing ellipsis) 
f(c, 1UL, 3.5f); 

сейчас c преобразуется в int, потому что введен первый параметр, а второй и третий аргументы по умолчанию продвигаются так же, как и раньше, поскольку они передаются как часть многоточия. Определение f должно теперь использовать ту же декларацию. Если вы это сделаете, передача аргументов способом, доступным для объектов <stdarg.h>, может потребовать предварительного знания от компилятора, поэтому перед выполнением вызова вам необходимо предоставить список параметров.

1

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

int main(int argc,char** argv) 
{ 
    f(3.0f); /* undefined behavior */ 
    g(3.0); /* undefined behavior */ 
} 

int f(float v) 
{ 
    return v; 
} 

int g(double v,...) 
{ 
    return v; 
} 

В этом примере, когда f называется, не прототип не был объявлен, так 3.0f повышается до double. Тем не менее, функция позже определяется с прототипом, который принимает float вместо double, поэтому поведение не определено.

Аналогично для g поведение не определено, поскольку эллипсы используются в прототипе определения.

+1

Этот стандарт C является странным. Где задействовано многоточие, которое вы показываете мне? Потому что они существуют в стандартном заявлении, который я выделил. – AnArrayOfFunctions

+0

@FISOCPP Выделив предложение, вы упомянули два случая, один из которых связан с параметрами '...'. Пример Вона Катона относится к другому делу. – fuz

+1

@FISOCPP: раздел, который вы выделили, предназначался для двух разных случаев. Я также добавил свой ответ, чтобы включить случай elipses. –