How to fix gcc error: expected while before void

2019-01-27 01:23发布

问题:

So I am writing a peer-to-peer chat client that uses pthreads to manage all the IO and when I compile the file gcc gives me the error

client.c: In function ‘accepted_daemon’:
client.c:115:1: error: expected ‘while’ before ‘void’
 void *
 ^
client.c: In function ‘listen_daemon’:
client.c:176:1: error: expected ‘while’ before ‘int’
 int main(int argc, char *argv[])
 ^

The source code for my program is

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>

#include <unistd.h>
#include <pthread.h>
#include <readline/readline.h>
#include <error.h>

#define error(s, e, ...) error_at_line (s, e, __FILE__, __LINE__, __VA_ARGS__)

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 3248
#define PROMPT "message: "

struct accepted 
{
  int fd;
  struct sockaddr_in addr;
};

struct value
{
  struct accepted *acc;
  struct value *nxt;
};

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct value *remote = NULL;

void
push_remote (struct accepted *acc)
{
  pthread_mutex_lock (&mutex);
  struct value *s = malloc (sizeof *s);
  s->acc = acc;
  s->nxt = remote;
  remote = s;
  pthread_mutex_unlock (&mutex);
}

void
pop_remote (struct accepted *acc)
{
  pthread_mutex_lock (&mutex);
  struct value head = { NULL, remote };
  struct value *s = &head;
  while (s->nxt->acc != acc)
    {
      s = s->nxt;
      if (s->nxt == NULL)
    return;
    }
  struct value *tmp = s->nxt->nxt;
  free (s->nxt);
  s->nxt = tmp;
} 

struct accepted *
make_socket (uint32_t s_addr)
{
  struct accepted *addr = malloc (sizeof *addr);
  addr->fd = socket (PF_INET, SOCK_STREAM, 0);
  if (addr->fd < 0)
    {
      free (addr);
      return NULL;
    }

  addr->addr.sin_family = AF_INET;
  addr->addr.sin_port = htons (PORT);
  addr->addr.sin_addr.s_addr = s_addr;

  if (connect (addr->fd, (struct sockaddr *) &addr->addr, 
           sizeof addr->addr) < 0)
    {
      free (addr);
      return NULL;
    }

  return addr;
}

void *
accepted_daemon (void *arg)
{
  pthread_cleanup_push (free, arg);
  struct accepted *args = arg;
  pthread_cleanup_push (close, args->fd);
  push_remote (args);
  pthread_cleanup_push (pop_remote, args);

  while (1)
    {
      char buffer[100];
      ssize_t chars = read (args->fd, buffer, sizeof buffer);
      if (chars < 0)
    {
      error (0, errno, "Host %s disconnected", 
        inet_ntop (AF_INET, arg, buffer, sizeof buffer));
      return NULL;
    }
      write (1, buffer, chars);
      write (1, "\n", strlen ("\n") * sizeof (char));
    }
  return NULL;
}

void *
initial_connection (void *arg)
{
  uint32_t host = (uint32_t) arg;
  struct accepted *acc = make_socket (arg);
  if (acc == NULL)
    {
      char buffer[100];
      error (1, errno, "Failed to connect to host %s", 
       inet_ntop (AF_INET, arg, buffer, sizeof buffer));
    }

  while (1)
    {
      uint32_t nxthost;
      read (sock, &nxthost, sizeof nxthost);
      if (nxthost == 0)
    break;
      pthread_t thread;
      pthread_create (&thread, NULL, initial_connection, (void *) nxthost);
    }

  return accepted_daemon (acc);
}


void *
listen_daemon (void *arg)
{
  int sock = socket (PF_INET, SOCK_STREAM, 0);
  pthread_cleanup_push (close, sock);
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons (PORT);
  addr.sin_addr.s_addr = INADDR_ANY;

  bind (sock, (struct sockaddr *) &addr, sizeof addr);
  listen (sock, 5);

  while (1)
    {
      struct accepted *acc = malloc (sizeof *acc);
      socklen_t len;
      acc->fd = accept (sock, (struct sockaddr *) &acc->addr, &len);

      pthread_mutex_lock (&mutex);
      struct value *p = remote;
      while (p != NULL)
    {
      write (acc->fd, &p->acc->addr.sin_addr.s_addr, sizeof (uint32_t));
      p = p->nxt;
    }
      pthread_mutex_unlock (&mutex);

      pthread_t thread;
      pthread_create (&thread, NULL, accepted_daemon, (void *) acc);
    }
  return NULL;
}


int main(int argc, char *argv[])
{
  assert (argc == 2);

  struct hostent *target = gethostbyname2 (argv[1], AF_INET);
  if (target == NULL)
    error (1, errno, "Host could not be found");

  pthread_t thread;
  pthread_create (&thread, NULL, initial_connection, 
          (void *) inet_addr (target->h_addr));

  pthread_create (&thread, NULL, listen_daemon, NULL);

  char *in = readline (PROMPT);
  while (in != NULL)
    {
      pthread_mutex_lock (&mutex);
      struct value *p = remote;
      while (p != NULL)
    {
      write (p->addr->fd, in, strlen (in));
      p = p->nxt;
    }
      pthread_mutex_unlock (&mutex);
      free (in);
      in = readline (PROMPT);
    }

  return 0;
}

回答1:

pthread_cleanup_push() most likely is implemented as a macro introducing an open brace { which expects a (corresponding) pthread_cleanup_pop() in the same context. The latter then serves the closing brace }. *1

Have a look at the pre-processor output of the code (and into the according man-pages and header files of course) and you'll get enlightened.


*1 This kind of implementation, BTW, is the most rigorous way I ever saw to discipline C coders ... ;->