2017-02-04 4 views
6

От K & R Книга на C, я понял, что если объявление прототипа функции опускает аргументы (как в int foo();), проверка типов и аргументов отключена, и ничего не предполагается относительно аргументов быть совместимым со старыми версиями C и поэтому он не нарушает устаревший код.Функциональный прототип - Отключение проверки аргументов

Но следующий код вызывает ошибку компиляции, что несоответствие прототипов:

#include <stdio.h> 
void test(); 
int main(void) { 
    test(34.5f); 
} 

void test(float a) { 
    printf("%f\n", a); 
} 

Ошибка:

C:\***.c:7:6: error: conflicting types for 'test' 
void test(float a) { 
    ^

Любые объяснения?

+5

gcc добавляет: 'примечание: тип аргумента с объявлением по умолчанию не может совпадать с объявлением списка пустых параметров', поэтому 'void test (double a)' работает, но 'void test (float a)' doesn «т. Таким образом, кажется, что «проверка типов и аргументов отключена и ничего не принимается в отношении аргументов» - это упрощение. Вы должны обратиться к спецификации C, чтобы узнать, что такое правило. – ikegami

+0

См. Http://stackoverflow.com/questions/1630631/alternative-kr-c-syntax-for-function-declaration-versus-prototypes. Этот вопрос может рассматриваться некоторыми как дубликат этого и завершаться закрытым. –

+1

Компилятор ожидает определения 'void test (double a) {}', как 'test (34.5f);' call включает в себя _default arguments promotionions, что имеет место, если данное объявление не служит прототипом. Одним из таких продвижений является 'float ---> double'. –

ответ

-1

Вы сказали gcc составить c11 код, а не как K & Р.

Я смотрел на -std= вариантов, но ни один из них не выделяются как полезные. Возможно, отказ от стандартного языкового параметра поможет. Или укажите его как c89.

В c11 всегда требуются полноформатные прототипы. Поэтому первое использование дает функцию с параметром = (void). В pre-C++ это действительно означало бы «могут быть или не быть переданные параметры».

+0

«В c11 всегда требуются прототипы в форме полной формы». Цитата? – Ryan

+0

nope, попробовал c89. Не скомпилировался и с этим. – BalaK

+0

@ Ryan: Разве это не одно из главных усовершенствований c11? Или, может быть, я думаю о C++ 11? – wallyk

5

Если функция объявлена ​​более одного раза, все объявления должны иметь совместимый тип (C11 6.2.7/2). В вашем коде f объявляется дважды - определение также считается объявлением.

Определение "совместимой функции типа" в С11 6.7.6.3/15:

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

Поэтому void test() и void test(float) несовместимы. Другими словами, после просмотра void test();, любой прототип должен использовать только те типы, которые не изменяются по умолчанию. float изменяется на double под этими акциями.

Я считаю, что это всегда имело место со времен первого стандарта C.

1

Определите функцию с параметром типа double.

void test(double a) { 
    //... 
} 

Проблема заключается в этом вызове

test(34.5f); 

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

+1

Код по-прежнему является нарушением ограничения даже без вызова функции –

0

Итак, наконец, из всех ответов, приведенных здесь и из небольшого количества чтений, вот что я узнал (я отправил его в качестве ответа, чтобы он был полезен любому, кто может столкнуться с этим вопросом в будущем) :

  • Когда я назвал test(23.4f) - параметр автоматически «принуждать» в два раза и будет называться test(double), поскольку ни прототип не определен (для аргументов, по крайней мере)
  • поскольку любой вызов я сделать с помощью каких-либо аргументов будет преобразован в «поощрение по умолчанию», я не могу иметь функции, объявленные как test(float), поскольку он никогда не будет использоваться/вызывать редактор Итак, test(double) работает и test(float) нет.

Исправьте меня, если я ошибаюсь, и я отредактирую свой ответ.

1

В соответствии с сообщением об ошибке тип аргумента, который имеет поощрение по умолчанию, не может соответствовать объявлению списка пустых параметров. Таким образом, проблема заключается в том, что float будет повышаться до int, что затем приведет к несоответствию с параметром определения функции float.

Декларация:

void test(); 

Это говорит компилятору, что существует функция test которой никакие параметры и не не возвращает значение.

Определение:

void test(float a) 

Это говорит компилятору, что test() на самом деле, а также предоставляет декларацию, а также.

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