объявление функции не является прототипом

Следующий код компилируется нормально:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

extern int errno ;

int main ( void )
{
    FILE *fp;
    int errnum;
    fp = fopen ("testFile.txt", "rb");

    if ( fp == NULL )
    {
        errnum = errno;
        fprintf( stderr, "Value of errno: %d\n", errno );
        perror( "Error printed by perror" );
        fprintf( stderr, "Error opening file: %s\n", strerror( errnum ) );
        exit( 1 );
    }

    fclose ( fp );
}

Но я не могу скомпилировать его с помощью:

gcc-8 -Wall -Wextra -Werror -Wstrict-prototypes

Я получаю следующее:

 program.c:6:1: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 extern int errno ;
 ^~~~~~
cc1: all warnings being treated as errors

Как этого избежать/исправить? Мне нужен этот флаг компилятора -Wstrict-prototypes


person Michi    schedule 07.07.2018    source источник
comment
Вы не должны никогда объявлять errno самостоятельно. Он не должен быть переменной (это может быть макрос, вызывающий функцию, что встречается очень часто).   -  person Some programmer dude    schedule 07.07.2018


Ответы (1)


extern int errno ;

неправильно. Вы должны просто удалить эту строку.

Происходит то, что вы включаете <errno.h>, который определяет макрос с именем errno. А на самом деле ...

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

(Это из C99, 7.5 Errors <errno.h>.)

В вашем случае errno, вероятно, расширяется до чего-то вроде (*__errno()), поэтому ваше объявление становится

extern int (*__errno());

который объявляет __errno как функцию (с неуказанным списком параметров), возвращающую указатель на int.

person melpomene    schedule 07.07.2018
comment
Что ж, вы правы, и в руководстве сказано: Не делайте этого ===›› On some ancient systems, <errno.h> was not present or did not declare errno, so that it was necessary to declare errno man‐ ually (i.e., extern int errno). Do not do this. It long ago ceased to be necessary, and it will cause problems with mod‐ ern versions of the C library. Вы можете добавить это в свой ответ, если хотите. - person Michi; 07.07.2018
comment
Кстати, вы были правы, это прекрасно компилируется ==›› extern int (*__errno(void)); (я не буду его использовать), что делает ваш ответ верным. - person Michi; 07.07.2018