例えば:
#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の一般的なパラダイムは次のとおりです(NSString
、id
、および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
その理由は、スイッチが整数値のみを許可するためであるように思われます(コンパイラの警告が言ったように)。だから私はもっと良い質問はなぜこれが事実であるかを尋ねることだろうと思いますか? (おそらく今では手遅れですが。)
Switchステートメントは整数値でのみ動作します。そのため、エラーメッセージは「整数ではなく数量を切り替えてください」です。言語構文の外にあるので、技術的な制限ではないと思います。
定数ポインター式が1つしかない場合、switch
ステートメントにはポインター式を提供するものがほとんどありません。あなたは本質的に唯一の可能な構造を引用しました。
switch
ステートメントは、整数式でのみ機能します。ポインタは整数式ではありません。
必要に応じて、ポインタを整数型に明示的に変換できますが、提案されたコードは少し奇妙で不自然です。
つまり、質問に正確に答えるには、ポインターと整数型の間に暗黙の変換がないためです。
スイッチは、変数を一連のコンパイル時定数と比較します。 null以外に、ポインターと比較できる有効なコンパイル時定数が表示されません。例えば:
switch (ptr) {
case &var1: printf ("Pointing to var1"); break;
case &var2: printf ("Pointing to var2"); break;
}
var1とvar2は、プログラムの実行ごとに異なる可能性があり、コンパイル時定数ではありません。 1つの可能性は、それらが常に固定されているメモリマップポートのアドレスである可能性がありますが、そうでない場合、2つのケース(null/not-null)からこれを簡単に拡張する方法がわかりません。
Ptrをintにキャストして、再試行してください。
switch( (int)ptr )
またはより正確に:
switch( (intptr_t)ptr ) // C99 integer type to hold a pointer
できます(本当に必要な場合)。 適切なサイズの整数にポインタをキャストするだけです。このため 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;
}
case
ラベルは定数式(通常は整数)を想定しており、NULLの場合を除いて、ポインターはこれらと十分に比較されない傾向があります。 intptr_tにキャストすることもできますが、比較できるものが1つしかない場合は、それでも無意味です。
switch
ステートメントが存在するのは、コンパイラーがそれらを ジャンプテーブル に変換できることが多いためです。これは、ケースラベルが連続した整数である場合に最適な概念です。しかし、整数型にキャストされたポインターの場合、より面倒な構文を除いて、switchを使用してもif
/else
を超えるものは何も得られません。
これは、スイッチの実装方法に関連している可能性があります。ポインターでは不可能な特定のCPUレジスターを使用できるように、最大で整数を期待しているようです。