Switch-Case wird nach dem Auskommentieren einer nicht verwendeten Zeile nicht kompiliert

82

Hier ist mein Code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main (void) {

  struct addrinfo hints; 
  memset (&hints, 0, sizeof hints);

  hints.ai_family = AF_UNSPEC; 
  hints.ai_socktype = SOCK_DGRAM;  
  hints.ai_flags = AI_CANONNAME;   

  struct addrinfo *res;

  getaddrinfo ("example.com", "http", &hints, &res);
  printf ("Host: %s\n", "example.com");

  void *ptr;

  while (res != NULL) {
    printf("AI Family for current addrinfo: %i\n", res->ai_family);
    switch (res->ai_family) {
      case AF_INET:
        ptr = (struct sockaddr_in *) res->ai_addr;
        struct sockaddr_in *sockAddrIn = (struct sockaddr_in *) res->ai_addr;
        break;
    }
    res = res->ai_next;
  }
  return 0;
}

was gut kompiliert.

Wenn ich jedoch diese Zeile auskommentiere:

//ptr = (struct sockaddr_in *) res->ai_addr;

Ich werde bekommen:

$ gcc ex4.c
ex4.c:30:9: error: expected expression
        struct sockaddr_in *sockAddrIn = (struct sockaddr_in *) res->ai_addr;
        ^
1 error generated.

Was vermisse ich?

Koray Tugay
quelle
Vielleicht sollte der Titel dieser Frage bearbeitet werden? Kann jemand, der mehr Erfahrung hat, dies tun, wenn er damit einverstanden ist?
Koray Tugay
Sie sollten es selbst bearbeiten können, wenn Sie möchten. Aber ich stimme zu, der Titel könnte besser sein.
Frage
@KorayTugay, ich habe es versucht.
Paul Draper
1
Eine Variablendeklaration in a zu haben case(ohne umgebende geschweifte Klammern, wie in der oberen Antwort vorgeschlagen), ist eine schlechte Idee, da der Name der Variablen in späteren cases sichtbar ist, aber nicht initialisiert wird (es sei denn, Sie haben ihn fallen gelassen).
MM

Antworten:

111

Jeder Fall in einer switch-Anweisung ist technisch gesehen ein Label. Aus obskuren und alten Gründen dürfen Sie keine Variablendeklaration als erste Zeile nach einem Label haben. Durch Auskommentieren der Aufgabe

ptr = (struct sockaddr_in *) res->ai_addr;

die Linie

struct sockaddr_in *sockAddrIn = (struct sockaddr_in *) res->ai_addr;

wird die erste Zeile nach dem Etikett, AF_INET:was, wie gesagt, in C illegal ist.

Die Lösung besteht darin, alle Ihre Fallaussagen wie folgt in geschweifte Klammern zu setzen:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main (void) {

  struct addrinfo hints; 
  memset (&hints, 0, sizeof hints);

  hints.ai_family = AF_UNSPEC; 
  hints.ai_socktype = SOCK_DGRAM;  
  hints.ai_flags = AI_CANONNAME;   

  struct addrinfo *res;

  getaddrinfo ("example.com", "http", &hints, &res);
  printf ("Host: %s\n", "example.com");

  void *ptr;

  while (res != NULL) {
    printf("AI Family for current addrinfo: %i\n", res->ai_family);
    switch (res->ai_family) {
      case AF_INET:
      {
        ptr = (struct sockaddr_in *) res->ai_addr;
        struct sockaddr_in *sockAddrIn = (struct sockaddr_in *) res->ai_addr;
        break;
      }
    }
    res = res->ai_next;
  }
  return 0;
}

Jedenfalls denke ich, dass dies eine bessere Codierungspraxis ist.

johnny_boy
quelle
22
Nett. Nitpicking "Jeder Fall ... ist ... eine beschriftete Aussage". Und das ist der Grund: Aussagen können beschriftet werden, aber keine Deklarationen.
undur_gongor
4
@KorayTugay Manchmal sind Compiler-Nachrichten nicht so informativ, wie wir sie haben wollen ... manchmal sind sie zu informativ (Husten C ++ stl Husten).
johnny_boy
5
@ BlueMoon Du hast recht. Wenn Sie ein Tool zur Vereinfachung von C ++ stl-Fehlermeldungen kaufen können, wissen Sie, dass die Informationsdichte unglaublich niedrig ist!
johnny_boy
3
oder verschieben Sie einfach die Deklarationen vor dem Schalterblock
Pavel Gatnar
3
@immibis: In C ++ sind Deklarationen Anweisungen, weshalb Sie in C ++ Deklarationen ohne Einschränkungen kennzeichnen können. In C sind Deklarationen keine Anweisungen, weshalb Sie sie nicht kennzeichnen können. Hier ist ein Beispiel, das diesen Unterschied zwischen C und C ++ veranschaulicht
AnT
15

Als Ergänzung zur akzeptierten Antwort können Sie Ihre Variablen vor den Fallbezeichnungen deklarieren.

switch(a) {
    int b; //can't initialize variable here
    case 0:
    ...
}

Oder verwenden Sie einfach eine leere Anweisung.

Matías Marquez
quelle