web-dev-qa-db-ja.com

なぜポインタをオンにしないのですか?

例えば:

#include <stdio.h>

void why_cant_we_switch_him(void *ptr)
{
    switch (ptr) {
        case NULL:
            printf("NULL!\n");
            break;
        default:
            printf("%p!\n", ptr);
            break;
    }
}

int main(void)
{
    void *foo = "toast";
    why_cant_we_switch_him(foo);
    return 0;
}

gcc test.c -o test
test.c: In function 'why_cant_we_switch_him':
test.c:5: error: switch quantity not an integer
test.c:6: error: pointers are not permitted as case values

ちょっと興味があるんだけど。これは技術的な制限ですか?

編集

定数ポインタ式は1つだけだと思われているようです。しかし、それは本当に本当ですか?たとえば、Objective-Cの一般的なパラダイムは次のとおりです(NSStringid、およびnilを除いて、実際にはCのみであり、これらは単なるポインタであるため、まだ関連性があります—これは技術的な質問にすぎませんが、実際にはisが一般的に使用されていることを指摘したいと思います):

#include <stdio.h>
#include <Foundation/Foundation.h>

static NSString * const kMyConstantObject = @"Foo";

void why_cant_we_switch_him(id ptr)
{
    switch (ptr) {
        case kMyConstantObject: // (Note that we are comparing pointers, not string values.)
            printf("We found him!\n");
            break;
        case nil:
            printf("He appears to be nil (or NULL, whichever you prefer).\n");
            break;
        default:
            printf("%p!\n", ptr);
            break;
    }
}

int main(void)
{
    NSString *foo = @"toast";
    why_cant_we_switch_him(foo);
    foo = kMyConstantObject;
    why_cant_we_switch_him(foo);

    return 0;
}

gcc test.c -o test -framework Foundation
test.c: In function 'why_cant_we_switch_him':
test.c:5: error: switch quantity not an integer
test.c:6: error: pointers are not permitted as case values

その理由は、スイッチが整数値のみを許可するためであるように思われます(コンパイラの警告が言ったように)。だから私はもっと良い質問はなぜこれが事実であるかを尋ねることだろうと思いますか? (おそらく今では手遅れですが。)

28
Michael

Switchステートメントは整数値でのみ動作します。そのため、エラーメッセージは「整数ではなく数量を切り替えてください」です。言語構文の外にあるので、技術的な制限ではないと思います。

8
Jeff Kelley

定数ポインタ式が1つしかないため

定数ポインター式が1つしかない場合、switchステートメントにはポインター式を提供するものがほとんどありません。あなたは本質的に唯一の可能な構造を引用しました。

12
DigitalRoss

switchステートメントは、整数式でのみ機能します。ポインタは整数式ではありません。

必要に応じて、ポインタを整数型に明示的に変換できますが、提案されたコードは少し奇妙で不自然です。

つまり、質問に正確に答えるには、ポインターと整数型の間に暗黙の変換がないためです。

8
Brian R. Bondy

スイッチは、変数を一連のコンパイル時定数と比較します。 null以外に、ポインターと比較できる有効なコンパイル時定数が表示されません。例えば:

switch (ptr) { 
   case &var1: printf ("Pointing to var1"); break;
   case &var2: printf ("Pointing to var2"); break;
}

var1とvar2は、プログラムの実行ごとに異なる可能性があり、コンパイル時定数ではありません。 1つの可能性は、それらが常に固定されているメモリマップポートのアドレスである可能性がありますが、そうでない場合、2つのケース(null/not-null)からこれを簡単に拡張する方法がわかりません。

8
Tarydon

Ptrをintにキャストして、再試行してください。

switch( (int)ptr )

またはより正確に:

switch( (intptr_t)ptr ) // C99 integer type to hold a pointer
7
Justicle

できます(本当に必要な場合)。 適切なサイズの整数にポインタをキャストするだけです。このため intptr_t 使用すべきです。それは私がそれをお勧めすると言っているわけではありませんが、あなたにはあなたの理由があるかもしれません。

#include <stdint.h>
#include <stdio.h>

void we_can_switch_him(void *ptr)
{
    switch ((intptr_t)ptr) {
        case (intptr_t)NULL:
            printf("NULL!\n");
            break;
        default:
            printf("%p!\n", ptr);
            break;
    }
}

int main(void)
{
    void *foo = "toast";
    we_can_switch_him(foo);
    return 0;
}
4
Clifford

caseラベルは定数式(通常は整数)を想定しており、NULLの場合を除いて、ポインターはこれらと十分に比較されない傾向があります。 intptr_tにキャストすることもできますが、比較できるものが1つしかない場合は、それでも無意味です。

switchステートメントが存在するのは、コンパイラーがそれらを ジャンプテーブル に変換できることが多いためです。これは、ケースラベルが連続した整数である場合に最適な概念です。しかし、整数型にキャストされたポインターの場合、より面倒な構文を除いて、switchを使用してもif/elseを超えるものは何も得られません。

2
Dan Olson

これは、スイッチの実装方法に関連している可能性があります。ポインターでは不可能な特定のCPUレジスターを使用できるように、最大​​で整数を期待しているようです。

1
Otávio Décio