ошибка: «struct addrinfo», объявленная внутри списка параметров, не будет видна за пределами этого определения или объявления [-Werror]|

Я получаю это, если пытаюсь скомпилировать с одним из стандартов C:

-std=c99, -std=c11 or -std=c17 .

Если я удалю их, компилируется нормально, или если я использую -std=gnuXX, тоже работает

Почему так происходит, потому что я просто не могу это исправить.

программа.с:

#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>

#define PORT "5555"
#define BACKLOG 5

int getAdr_fd(struct addrinfo server, struct addrinfo **res );
int create_fd( struct addrinfo **res );
int accept_fd( struct sockaddr_storage *their_addr, int *sockfd );
int list_fd( int *sockfd );
int bind_fd( struct addrinfo **res, int *sockfd );
ssize_t write_fd( const char *const msg, int *new_fd );

int main(void){
    const char *msg = "Hello socket World!\n";
    struct sockaddr_storage their_addr;
    struct addrinfo server, *res;
    int sockfd, new_fd;

    /* create a socket: */
    getAdr_fd( server, &res );
    sockfd = create_fd( &res );

    /* Bind */
    bind_fd( &res, &sockfd );

    /* Listen */
    list_fd( &sockfd );

    /* Accept connection: */
    new_fd = accept_fd( &their_addr, &sockfd );

    /* Write */
    write_fd( msg, &new_fd );

    /* close: */
    close(sockfd);
    freeaddrinfo(res);
 }

 int getAdr_fd(struct addrinfo server, struct addrinfo **res ){
    int getfd;

    /* Create address structs with getaddrinfo(): */

    memset(&server, 0, sizeof server);
    server.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
    server.ai_socktype = SOCK_STREAM;
    server.ai_flags = AI_PASSIVE; // fill in my IP for me

    getfd = getaddrinfo( NULL, PORT, &server, res);
    if (getfd != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror( getfd ));
        exit(EXIT_FAILURE);
    }else{
        printf("getaddrinfo() \tOK\n");
        return getfd;
    }
}

int create_fd( struct addrinfo **res ){
    int sockfd = socket((*res)->ai_family, (*res)->ai_socktype, (*res)->ai_protocol);
    if (sockfd == -1 ){
        printf("Error, socket()\n");
        exit ( EXIT_FAILURE );
    }else{
        printf("socket() \tOK\n");
        return sockfd;
    }
}

int bind_fd( struct addrinfo **res, int *sockfd ){
    int bindfd = bind(*sockfd, (*res)->ai_addr, (*res)->ai_addrlen);
    if (bindfd == -1 ){
        printf("Error, bind(), check line 34\n");
        exit ( EXIT_FAILURE );
    }else{
        printf("bind() \t\tOK\n");
        return bindfd;
    }
}

int accept_fd(  struct sockaddr_storage *their_addr, int *sockfd  ){
    int new_fd;
    socklen_t addr_size = sizeof( *their_addr );
    new_fd = accept(*sockfd, (struct sockaddr *)their_addr, &addr_size);
    if (new_fd == -1 ){
        printf("Error, accept()\n");
        exit ( EXIT_FAILURE );
    }else{
        printf("accept() \tOK\n");
        return new_fd;
    }
}

int list_fd( int *sockfd ){
    int listfd = listen(*sockfd, BACKLOG);
    if (listfd == -1 ){
        printf("Error, listen()\n");
        exit ( EXIT_FAILURE );
    }else{
        printf("listen() \tOK\n");
        return listfd;
    }
}

ssize_t write_fd( const char *const msg, int *new_fd ){
    size_t len = strlen(msg);
    ssize_t wrtfd;
    wrtfd = write(*new_fd, msg, len );
    if (wrtfd == -1 ){
        printf("Error, write()\n");
        exit ( EXIT_FAILURE );
    }else{
        printf("write() \tOK\n");
    }

    return wrtfd;
}

Флаги компилятора:

-Wpedantic -Wall -Wextra -Werror -std=c17 -Wstrict-prototypes  -Wmissing-prototypes -Wmisleading-indentation -Wduplicated-cond -Wold-style-definition -Wconversion -Wshadow -Winit-self -Wfloat-equal -Wwrite-strings -Wcast-align=strict -Wformat -O0 -g

Выход:

program.c:14:22: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
 int getAdr_fd(struct addrinfo server, struct addrinfo **res );
                      ^~~~~~~~
program.c:15:23: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
 int create_fd( struct addrinfo **res );
                       ^~~~~~~~
program.c:18:21: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
 int bind_fd( struct addrinfo **res, int *sockfd );
                     ^~~~~~~~
program.c: In function ‘main’:
program.c:24:21: error: storage size of ‘server’ isn’t known
     struct addrinfo server, *res;
                     ^~~~~~
program.c:28:16: error: type of formal parameter 1 is incomplete
     getAdr_fd( server, &res );
                ^~~~~~
program.c:28:24: error: passing argument 2 of ‘getAdr_fd’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     getAdr_fd( server, &res );
                        ^~~~
program.c:14:57: note: expected ‘struct addrinfo **’ but argument is of type ‘struct addrinfo **’
 int getAdr_fd(struct addrinfo server, struct addrinfo **res );
                                       ~~~~~~~~~~~~~~~~~~^~~
program.c:29:25: error: passing argument 1 of ‘create_fd’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     sockfd = create_fd( &res );
                         ^~~~
program.c:15:34: note: expected ‘struct addrinfo **’ but argument is of type ‘struct addrinfo **’
 int create_fd( struct addrinfo **res );
                ~~~~~~~~~~~~~~~~~~^~~
program.c:32:14: error: passing argument 1 of ‘bind_fd’ from incompatible pointer type [-Werror=incompatible-pointer-types]
     bind_fd( &res, &sockfd );
              ^~~~
program.c:18:32: note: expected ‘struct addrinfo **’ but argument is of type ‘struct addrinfo **’
 int bind_fd( struct addrinfo **res, int *sockfd );
              ~~~~~~~~~~~~~~~~~~^~~
program.c:45:5: error: implicit declaration of function ‘freeaddrinfo’ [-Werror=implicit-function-declaration]
     freeaddrinfo(res);
     ^~~~~~~~~~~~
program.c:24:21: error: unused variable ‘server’ [-Werror=unused-variable]
     struct addrinfo server, *res;
                     ^~~~~~
program.c: At top level:
program.c:48:23: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
  int getAdr_fd(struct addrinfo server, struct addrinfo **res ){
                       ^~~~~~~~
program.c:48:32: error: parameter 1 (‘server’) has incomplete type
  int getAdr_fd(struct addrinfo server, struct addrinfo **res ){
                ~~~~~~~~~~~~~~~~^~~~~~
program.c: In function ‘getAdr_fd’:
program.c:56:23: error: ‘AI_PASSIVE’ undeclared (first use in this function); did you mean ‘AF_WANPIPE’?
     server.ai_flags = AI_PASSIVE; // fill in my IP for me
                       ^~~~~~~~~~
                       AF_WANPIPE
program.c:56:23: note: each undeclared identifier is reported only once for each function it appears in
program.c:58:13: error: implicit declaration of function ‘getaddrinfo’; did you mean ‘getAdr_fd’? [-Werror=implicit-function-declaration]
     getfd = getaddrinfo( NULL, PORT, &server, res);
             ^~~~~~~~~~~
             getAdr_fd
program.c:60:46: error: implicit declaration of function ‘gai_strerror’; did you mean ‘strerror’? [-Werror=implicit-function-declaration]
         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror( getfd ));
                                              ^~~~~~~~~~~~
                                              strerror
program.c:60:40: error: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Werror=format=]
         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror( getfd ));
                                       ~^     ~~~~~~~~~~~~~~~~~~~~~
                                       %d
program.c:48:32: error: unused parameter ‘server’ [-Werror=unused-parameter]
  int getAdr_fd(struct addrinfo server, struct addrinfo **res ){
                ~~~~~~~~~~~~~~~~^~~~~~
program.c: At top level:
program.c:68:23: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
 int create_fd( struct addrinfo **res ){
                       ^~~~~~~~
program.c:68:5: error: conflicting types for ‘create_fd’
 int create_fd( struct addrinfo **res ){
     ^~~~~~~~~
program.c:15:5: note: previous declaration of ‘create_fd’ was here
 int create_fd( struct addrinfo **res );
     ^~~~~~~~~
program.c: In function ‘create_fd’:
program.c:69:31: error: dereferencing pointer to incomplete type ‘struct addrinfo’
     int sockfd = socket((*res)->ai_family, (*res)->ai_socktype, (*res)->ai_protocol);
                               ^~
program.c: At top level:
program.c:79:21: error: ‘struct addrinfo’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
 int bind_fd( struct addrinfo **res, int *sockfd ){
                     ^~~~~~~~
program.c:79:5: error: conflicting types for ‘bind_fd’
 int bind_fd( struct addrinfo **res, int *sockfd ){
     ^~~~~~~
program.c:18:5: note: previous declaration of ‘bind_fd’ was here
 int bind_fd( struct addrinfo **res, int *sockfd );
     ^~~~~~~
program.c: In function ‘bind_fd’:
program.c:80:38: error: dereferencing pointer to incomplete type ‘struct addrinfo’
     int bindfd = bind(*sockfd, (*res)->ai_addr, (*res)->ai_addrlen);
                                      ^~
cc1: all warnings being treated as errors

Еще одна странная вещь, которую я замечаю, это:

program.c:45:5: error: implicit declaration of function ‘freeaddrinfo’ [-Werror=implicit-function-declaration]
 freeaddrinfo(res);

Но включаемые файлы есть:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.

Linux Mint 19, GCC-8.0.1.


person Michi    schedule 04.10.2018    source источник
comment
Используемый вами режим не определяет автоматически соответствующий макрос тестирования функций для объявления getadddrinfo() и друзей. Подробности смотрите на справочной странице.   -  person Shawn    schedule 04.10.2018
comment
@Shawn Режим, который я использую? Какой правильный путь, потому что я просто не могу понять.   -  person Michi    schedule 04.10.2018
comment
С11, С17 и т.д. Именно этот режим. Вы уже упомянули один правильный путь в своем посте. Вы также можете определить один из необходимых макросов тестирования функций перед включением каких-либо заголовков, если вы не хотите менять стандартный режим языка с простого.   -  person Shawn    schedule 04.10.2018


Ответы (2)


Это граничит с ошибкой glibc. Хотя это правда, что struct addrinfo не является частью стандарта C, так же как и <netdb.h>, поэтому не будет никакого вреда для его определения в этом заголовке (за исключением очень старых версий POSIX).

Вы по-прежнему можете указать любые стандартные параметры C и получить расширения GNU, если компилируете с помощью -D_GNU_SOURCE. См. документацию glibc и страницу руководства:

person Florian Weimer    schedule 04.10.2018

Функция getaddrinfo и, соответственно, тип struct addrinfo определяются POSIX. Это означает, что они не являются частью стандарта C.

Поэтому, когда вы указываете -std=c99, -std=c11 или -std=c17, эти типы исключаются, поскольку они не указаны в стандарте. Указание параметра -std=gnuxx включает определения этих типов.

person dbush    schedule 04.10.2018