поведение неявного объявления функции

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

test1

    #include <stdio.h>
    #include <limits.h>
    void main(){
        char c='\0';
        float f=0.0;
           xof(c,f);/* at this point implicit function declaration is 
generated as int xof(int ,double ); */ 
    }
    int xof(char c,float f)
    {
        printf("%d %f\n", c,f);
    }

Неявное объявление функции будет иметь вид int xof (int, double);

ошибка

имя_переменной.c: 8: 5: ошибка: конфликтующие типы для 'xof' int xof (char c, float f)

Я понимаю это, потому что неявно сгенерированное объявление функции (по умолчанию целочисленное значение равно INT, а десятичное - DOUBLE) не соответствует следующему определению функции.

test2

#include <stdio.h>


 #include <limits.h>
    void main(){
        unsigned int a =UINT_MAX;
        int b=0;
        xof(a); /* implicit function declaration should be int xof(int); */
    }

    int xof(unsigned a,int b)
    {
        printf("%d %d\n", a,b);
    }

неявным объявлением функции будет int xof (int);, что должно противоречить определению функции.

Но это работает нормально (без ошибок), и на выходе 'a' ведет себя как значение 'int', а 'b' имеет 'undefined Garbage '

-1 12260176

Может кто-нибудь объяснить это. Заранее спасибо.


person manifold    schedule 03.07.2017    source источник
comment
C требует правильного объявления перед использованием. Все остальное недопустимо C! Следовательно, бессмысленно спрашивать, почему этот код C что-то делает - это не код C, и вы не используете совместимый со стандартом компилятор и не игнорируете предупреждения. И, судя по вашему вступлению, вы это прекрасно понимаете.   -  person too honest for this site    schedule 03.07.2017
comment
Более старые версии стандартного вывода аргументов функции C. Во втором примере можно обойти эти расплывчатые правила. Это одна из причин, по которой C перешел к обязательному обязательному предварительному объявлению.   -  person AShelly    schedule 03.07.2017
comment
Просто установите компилятор не старше 18 лет. Тогда вам не нужно об этом задумываться.   -  person Lundin    schedule 03.07.2017
comment
Проголосуйте за повторное открытие. Связанный дубликат спрашивает, нужны ли прототипы функций. Этот вопрос спрашивает, в каких случаях можно использовать неявное объявление.   -  person dbush    schedule 03.07.2017


Ответы (1)


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

В случае первой программы сгенерированное сообщение об ошибке:

/tmp/x1.c:10: ошибка: конфликтующие типы для 'xof'
/tmp/x1.c:10: примечание: тип аргумента с продвижением по умолчанию не может соответствовать объявлению списка пустых имен параметров < br> /tmp/x1.c:6: ошибка: здесь было предыдущее неявное объявление 'xof'

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

Вторая программа не генерирует ошибку, потому что ни один из аргументов (int и unsigned int) не подчиняется правилам продвижения по умолчанию. В этом случае вы вызываете неопределенное поведение, потому что вы не передаете нужное количество аргументов правильных типов. Если вы передали 2 параметра правильных типов, поведение было бы хорошо определено.

Обратите внимание, что неявные объявления функций являются функцией C89 и не поддерживаются в C99 и более поздних версиях, хотя некоторые компиляторы могут по-прежнему принимать их в режиме C99 или C11 в качестве расширения.

person dbush    schedule 03.07.2017