I was handed some C code that basically consists of a big main() function. I am now trying to unfold the method into smaller functions, to make clearer the code's intent. I am having some trouble, though:
void main(int argc, char *argv[])
{
if(argc != 3)
{
printf("Usage: table-server <port> <n_lists>\n");
return;
}
int port = atoi(argv[1]), n_lists = atoi(argv[2]);
if(port < 1024 || port > 49151 || n_lists < 1)
{
printf("Invalid args.\n");
return;
}
signal(SIGPIPE, SIG_IGN);
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(port);
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
{
printf("(bind).\n");
return;
}
if(listen(sockfd, SOMAXCONN) < 0)
{
printf("(listen).\n");
return;
}
I can identify 4 main concerns in this code's function:
- Verifying the number of args is correct.
- Getting from the command line arguments the port.
- Calling signal(SIGPIPE, SIG_IGN).
- Actually try to make a connection with the socket.
The problem when trying to refactor this into small functions is mainly related with error handling. For instance,r trying to extract the logic of 1. would look like this:
int verify_number_of_args(int argc) {
if (argc != 3) {
printf("...");
return -1;
}
return 0;
}
and calling it would be something like this
if (verify_number_of_args(argc) == -1) return;
which isn't actually that bad. Now, for the socket, that'd be way more troublesome as both sockfd
and s_addr
need to be returned, plus the status return value:
int sockfd;
struct sockaddr_in* s_addr;
if (create_socket(port, &sockfd, s_addr) == -1)
return;
which kind of defeats the purpose of trying to keep my main method as simple and clear as possible. I could, of course, resort to global variables in the .c
file but that doesn't seem that good of an idea.
How do you generally handle this kind of things in C?