未使用の行をコメントアウトした後、Switch-caseはコンパイルされません


82

これが私のコードです:

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

これは正常にコンパイルされます。

ただし、この行をコメントアウトすると、次のようになります。

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

私は手に入れます:

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

何が足りないのですか?


たぶん、この質問のタイトルを編集する必要がありますか?同意すれば、より経験豊富な誰かがこれを行うことができますか?
Koray Tugay 2015年

必要に応じて、自分で編集できるはずです。しかし、私は同意します、タイトルはもっと良いかもしれません。
QuestionC

@KorayTugay、私はそれを実行しました。
ポールドレイパー

1
case(一番上の答えで示唆されているように中括弧で囲まずに)変数宣言を中にcase入れることは悪い考えです。変数の名前は後のsで表示されますが、初期化されません(ドロップダウンしない限り)。
MM 2015年

回答:


111

switchステートメントの各ケースは、技術的に言えば、ラベルです。いくつかのあいまいで古い理由により、ラベルの後の最初の行として変数宣言を使用することは許可されていません。割り当てをコメントアウトすることによって

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

この線

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

AF_INET:私が言ったように、Cでは違法であるラベルの後の最初の行になります。

解決策は、次のようにすべてのcaseステートメントを中括弧で囲むことです。

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

とにかく、これはより良いコーディング方法だと思います。


22
いいね。「それぞれの場合は...ラベル付きのステートメントです」というニッチピッキング。そしてそれが理由です:ステートメントはラベル付けできますが、宣言はできません。
undur_gongor 2015年

4
@KorayTugayコンパイラメッセージは、私たちが望んでいるほど有益ではない場合があります....情報が多すぎる場合もあります(咳咳C ++ stl咳咳)。
ジョンM

5
@BlueMoonその通りです。C ++ stlエラーメッセージを単純化するツールを購入できると、情報密度が非常に低いことがわかります。
ジョンM

3
または、スイッチブロックの前に宣言を移動する
Pavel Gatnar 2015年

3
@immibis:C ++では宣言はステートメントです。そのため、C ++では制限なしで宣言にラベルを付けることができます。Cでは、宣言はステートメントではないため、ラベルを付けることはできません。ここではCとC ++の間のこの違いを示し例です:stackoverflow.com/a/19830820/187690
Antの

15

受け入れられた回答を補完するものとして、ケースラベルの前に変数を宣言できます。

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

または、空のステートメントを使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.