Switch-case no se compilará después de comentar una línea no utilizada

82

Aquí está mi código:

#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;
}

que se compila bien.

Sin embargo, cuando comento esta línea:

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

Obtendré:

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

¿Qué me estoy perdiendo?

Koray Tugay
fuente
¿Quizás debería editarse el título de esta pregunta? ¿Puede alguien con más experiencia hacer esto si está de acuerdo?
Koray Tugay
Debería poder editarlo usted mismo si lo desea. Pero estoy de acuerdo, el título podría ser mejor.
QuestionC
@KorayTugay, lo intenté.
Paul Draper
1
Tener una declaración de variable dentro de un case(sin llaves alrededor como lo sugiere la respuesta superior) es una mala idea porque entonces el nombre de la variable será visible en los últimos cases, pero no estará inicializado (a menos que baje).
MM

Respuestas:

111

Cada caso en una declaración de cambio es, técnicamente hablando, una etiqueta. Por algunas razones antiguas y oscuras , no se le permite tener una declaración de variable como primera línea después de una etiqueta. Al comentar la tarea

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

la línea

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

se convierte en la primera línea después de la etiqueta AF_INET:que, como dije, es ilegal en C.

La solución es envolver todas las declaraciones de su caso entre corchetes de esta manera:

#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;
}

De todos modos, creo que esta es una mejor práctica de codificación.

John M
fuente
22
Agradable. Nitpicking "Cada caso ... es ... una declaración etiquetada". Y esa es la razón: las declaraciones se pueden etiquetar pero no las declaraciones.
undur_gongor
4
@KorayTugay A veces, los mensajes del compilador no son informativos como queremos que sean ... a veces son demasiado informativos (cough cough C ++ stl cough cough).
John M
5
@BlueMoon Tienes razón. Cuando puede comprar una herramienta para simplificar los mensajes de error stl de C ++, ¡sabe que la densidad de información es increíblemente baja!
John M
3
o simplemente mueva las declaraciones antes del bloque de cambio
Pavel Gatnar
3
@immibis: En C ++, las declaraciones son declaraciones, por lo que en C ++ puede etiquetar declaraciones sin restricciones. En C, las declaraciones no son declaraciones, por lo que no puede etiquetarlas. Aquí hay un ejemplo que ilustra esta diferencia entre C y C ++: stackoverflow.com/a/19830820/187690
AnT
15

Como complemento a la respuesta aceptada, puede declarar sus variables antes de las etiquetas del caso.

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

O simplemente use una declaración vacía.

Matías Márquez
fuente