Is this a legitimate C++ code? [closed]

 ̄綄美尐妖づ 提交于 2019-12-19 10:14:57

问题


The code comes from here

Given that in C++ you can use C libraries would you say that the following code is a legitimate C++ code? If not what changes need to be applied?

This code compiles with g++ and runs as expected.

UPDATE: Thank you for all answers. I'm still slightly confused as there's no agreement on whether or not this code comply with C++ standards. Will ask another question to dispel my doubts

UPDATE2: To moderators who closed this question: Just noticed that the question has been closed which I think is ridiculous. It's a down-to-earth technical question and I received down-to-earth technical answers.In case you haven't read fully the whole thread, here's the visual representation of the conclusion we've agreed on:

Clearly C++ is not a superset of C.

Closing questions that deal with coding standards is just wrong.

Client:

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

    #include <arpa/inet.h>
    #define PORT "3490" // the port client will be connecting to 
    #define MAXDATASIZE 100 // max number of bytes we can get at once 

    // get sockaddr, IPv4 or IPv6:
    void *get_in_addr(struct sockaddr *sa){
        if (sa->sa_family == AF_INET) {
            return &(((struct sockaddr_in*)sa)->sin_addr);
        }

        return &(((struct sockaddr_in6*)sa)->sin6_addr);
    }

    int main(int argc, char *argv[]){
        int sockfd, numbytes;  
        char buf[MAXDATASIZE];
        struct addrinfo hints, *servinfo, *p;
        int rv;
        char s[INET6_ADDRSTRLEN];

        if (argc != 2) {
            fprintf(stderr,"usage: client hostname\n");
            exit(1);
        }

        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
            fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
            return 1;
        }

        // loop through all the results and connect to the first we can
        for(p = servinfo; p != NULL; p = p->ai_next) {
            if ((sockfd = socket(p->ai_family, p->ai_socktype,
                    p->ai_protocol)) == -1) {
                perror("client: socket");
                continue;
            }

            if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
                close(sockfd);
                perror("client: connect");
                continue;
            }

            break;
        }

        if (p == NULL) {
            fprintf(stderr, "client: failed to connect\n");
            return 2;
        }

        inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
                s, sizeof s);
        printf("client: connecting to %s\n", s);

        freeaddrinfo(servinfo); // all done with this structure

        if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
            perror("recv");
            exit(1);
        }

        buf[numbytes] = '\0';
        printf("client: received '%s'\n",buf);
        close(sockfd);

        return 0;
    }

Server:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define PORT "3490"  // the port users will be connecting to
#define BACKLOG 10     // how many pending connections queue will hold

void sigchld_handler(int s){
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void){
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }

        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }

        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    if (p == NULL)  {
        fprintf(stderr, "server: failed to bind\n");
        return 2;
    }

    freeaddrinfo(servinfo); // all done with this structure

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1) {  // main accept() loop
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("accept");
            continue;
        }

        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("server: got connection from %s\n", s);

        if (!fork()) { // this is the child process
            close(sockfd); // child doesn't need the listener
            if (send(new_fd, "Hello, world!", 13, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);  // parent doesn't need this
    }

    return 0;
}

回答1:


From your comments it seems like you're really interested in how portable the code is, or "how can you be sure that it will compile on any C++ compiler not just g++".

Since each compiler has s different set of extensions they support (or even a different level of how well they support the standard, or which standard they support), one way is to try compiling it with different compilers.

If you can't do that, you can specify exactly which set of extenstions and/or standards that gcc will use to compile. For example:

--std=c89
--std=c90
--std=c99
--std=gnu90      (default for C compiles)
--std=gnu99

--std=c++98
--std=c++0x
--std=gnu++98    (default for C++ compiles)
--std=gnu++0x

There are probably other, see the gcc docs for more detail: http://gcc.gnu.org/onlinedocs/gcc/Standards.html

Also, the --pedantic option can make gcc much more strict about standards compliance.




回答2:


Personally I see C++ are more declarative than C which is highly procedural (though not as declarative as things like prolog).

server

ServerAction   action;
Server         server(action);

EventLoop      loop(server);
loop.processes();

Client

Address        addr("123.45.67");
Connection     connect(addr);

Message        message(Connection::Type::HTTP, "Plop");
connection.Send(message);



回答3:


This does comply with C++ standards, and in that sense it is legally C++.

However, there is nothing here that is C++ specific. You could have just as easily compiled this with gcc.

I think what others are noting here is the fact that this code is written in a procedural way, not in an object-oriented way. Most people associate C++ with object-oriented programming, and most modern books that discuss morally responsible C++ programming would say this is a bad way to write an app. In other words, it is very much not in vogue to write programs like this when an object-oriented paradigm is available to write this sort of application in.

This application is very difficult to maintain, and is written almost haphazardly. A good C programmer would split this problem into multiple functions instead of dumping most of it in main(). It works as an example of how to do client-server, but I would hesitate to write new code like this.




回答4:


You’re not writing C++, you’re taking advantage of the fact that conforming, clean C code will compile as C++ with no problems. There are some places where C++ diverges from C, but the compiler will yell at you in those cases. You could use this as a base on top of which to write some effective C++; otherwise, there’s nothing special going on.




回答5:


This is valid, but not in the C++ preferred style.

For example, all the standard C libraries should be included <cstdio>, not <stdio.h>.

Another example, this code uses a #define when it could have used a constant integer.




回答6:


If I were to visit you at Scotland and speak Scottish with my Portuguese accent and (short) English vocabulary ... would you say I was speaking Scottish?

Assume everybody understood me and I understood everybody :-)




回答7:


Using C++, you could use better type checking features to avoid things like void*, #define, etc.

But since it does not use exclusive C features, it compiles with g++.




回答8:


It is 'C' code that also conforms to the compatible subset within C++.

If it compiles it's legitimate, absent compiler bugs, but it seems to me that you have a different meaning for 'legitimate'.




回答9:


I don't quite understand the question. I think you're asking whether you should just keep using it without any changes, and not worry about it - in which case I'd say yes. C++ is a superset of C - any valid C code is valid C++ code, as you see.

By convention, the standard headers have a new format -

#include <string.h>

becomes

#include <cstring>

but this isn't strictly necessary. You can't do that with the unistd and sys/ headers, anyway.

So if you're asking whether you can safely keep using it - go for it, but you may want to change errno.h to cerrno, stdio.h to cstdio, and so on.



来源:https://stackoverflow.com/questions/4372062/is-this-a-legitimate-c-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!