Подтвердить что ты не робот

Почему нет переключателей указателей?

Например:

#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

Просто любопытно. Это техническое ограничение?

ИЗМЕНИТЬ

Люди, похоже, думают, что существует только одно выражение константного указателя. Правда, правда? Например, здесь есть общая парадигма в Objective-C (это действительно только C в стороне от NSString, id и nil, которые являются просто указателями, поэтому они по-прежнему актуальны - я просто хотел указать что на самом деле это используется для него, несмотря на это только технический вопрос):

#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

Похоже, причина в том, что коммутатор допускает только интегральные значения (как предупреждал компилятор). Поэтому я полагаю, что лучший вопрос - спросить, почему это так? (хотя, вероятно, уже слишком поздно.)

4b9b3361

Ответ 1

Операторы коммутатора работают только с интегральными значениями. Поэтому сообщение об ошибке "количество переключателей не целое". Я не считаю это техническим ограничением, так как это вне синтаксиса языка.

Ответ 2

Поскольку существует только одно выражение константного указателя

Учитывая, что существует только одно выражение константного указателя, оператор switch мало что может предложить выражениям указателя. Вы процитировали по существу единственно возможную конструкцию.

Ответ 3

Операторы

switch работают только с интегральными выражениями. Указатель не является интегральным выражением.

Вы можете явно преобразовать указатель в интегральный тип, если хотите, но предлагаемый код немного странный и неестественный.

Итак, чтобы точно ответить на ваш вопрос: потому что нет никакого неявного преобразования между указателем и интегральным типом.

Ответ 4

Переведите ptr в int и повторите попытку:

switch( (int)ptr )

или, вернее,

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

Ответ 5

Коммутатор сравнивает переменную с набором констант времени компиляции. Помимо нуля, я не вижу никаких допустимых констант времени компиляции, с которыми вы могли бы сравнить указатель. Например:

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

var1 и var2, вероятно, различаются в каждом прогоне программы и не будут компилировать постоянные времени. Одна из возможностей может заключаться в том, что они являются адресами портов с отображением памяти, которые всегда исправлены, но в остальном я не вижу, как вы могли бы легко расширить это из двух ваших случаев (null/not-null).

Ответ 6

Это может быть связано с тем, как реализован коммутатор - он, по-видимому, ожидает максимум целых чисел, поэтому он может использовать определенный регистр ЦП, который может быть невозможен с помощью указателя.

Ответ 7

case метки ожидают постоянного выражения, обычно целого, и указатели, как правило, не сравниваются с ними, кроме как в случае NULL. Вы можете использовать для intptr_t, но это все еще бессмысленно, если у вас есть только одна вещь, с которой вы можете сравнить.

Операторы

switch существуют потому, что компилятор часто может превращать их в таблицу перехода которая представляет собой концепцию, которая лучше всего работает, если ваш случай ярлыки являются целыми целыми числами. Но в случае указателя, отлитого от целочисленного типа, вы ничего не получаете над if/else с помощью переключателя, кроме более громоздкого синтаксиса.

Ответ 8

Вы можете (если вы действительно должны). Просто наведите указатель на нужный размер. Для этого следует использовать 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;
}

Ответ 9

Doh! почему даже использовать оператор switch? Операторы switch должны использоваться только в том случае, если у вас есть 3 или более варианта, если у вас есть 2 варианта, то используйте оператор if() {} else {}.

joshua это не законное использование указателя в коммутаторе.

Если вы действительно должны использовать оператор switch, то переведите его на _int64 или long long или какой-либо целостный тип, который должен быть таким же большим или большим, чем указатель (зависит от компилятора).

Также некоторые компиляторы могут ограничить максимальный размер коммутатора на int или какой-либо другой произвольный размер. в этом случае вы вообще не можете использовать оператор switch.

DC

Ответ 10

enum boolean
{
 FALSE=0,
 TRUE=!FALSE
}boolean;
...
void *ptr=NULL;
...
switch((!ptr))
{
 case FALSE:
  ...
  break;
 case TRUE:
  ...;
  break;
}
...

Можно включить указатель.

Ответ 11

Вам нужно только это изменение в вашем коммутаторе: [ptr intvlue]

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