case switch: ошибка: метка case не сводится к целочисленной константе

int value;

const int signalmin = some_function();

switch(value)
{
   case signalmin:
   break;
}

Я прочитал значение some_function и использовал это значение int, чтобы сделать случай переключения. Компилятор C99 возвращает:

error: метка case не сводится к целочисленной константе

Но я не могу использовать #define, потому что значение int считывается до того, как коммутатор выполнит.

27

5 ответы

switch labels must be constant expressions, they have to be evaluated at compile time. If you want to branch on run-time values, you must use an if.

A const -qualified variable не является выражением константы , это просто значение, которое вам не разрешено изменять.

Форма целочисленных константных выражений подробно описана в 6.6 (6) [C99 и черновик стандарта n1570 стандарта C2011]:

6 Целочисленное константное выражение должно иметь целочисленный тип и должно иметь только операнды   которые являются целыми константами, константами перечисления, символьными константами, sizeof   выражения, результаты которых представляют собой целые константы, выражения _Alignof и плавающие   константы, которые являются непосредственными операндами приведения. Операторы Cast в целочисленной константе   выражение должно преобразовывать только арифметические типы в целые типы, за исключением как части   операнд к оператору sizeof или _Alignof .

Ограничение, в котором выражаются выражения sizeof , результат которых является целочисленной константой, исключает выражения sizeof , операнд которых является массивом переменной длины.

38
добавлено
спасибо за ясный ответ, я использую вместо этого.
добавлено автор Jim Clermonts, источник
Ну, const не является целым константным выражением, но как насчет static const ?
добавлено автор Cyan, источник
@Cyan Не в C (последний раз я смотрел). На других языках все может быть по-другому.
добавлено автор Daniel Fischer, источник
Хорошее решение, работает правильно.
добавлено автор delive, источник

В C. все метки case должны быть время компиляции . В C квалификатор const не создает константу времени компиляции, он просто обозначает, что переменная времени выполнения доступна только для чтения.

Переключатель не является подходящей структурой управления для того, что вы пытаетесь сделать.

5
добавлено

Позвольте мне включить пример. Следующее было протестировано в версии gcc 4.6.3 с флагом -std = c99 -pedantic :

#define SOME_HARDCODED_CONSTANT 0 //good
int foo(int i, int b){
    const int c=0; //bad
    int a=0; //bad

    switch(i){
        case c:     //compile error
        case a:     //compile error.
        case (b+a): //compile error
        case SOME_HARDCODED_CONSTANT: //all good
        case 5: //all good
    }
}

Как отмечали другие, аргументы case не могут быть оценены во время выполнения. Для этого используйте блок if-else .

5
добавлено
Ясно, что лучший ответ. Благодарю.
добавлено автор Noel, источник

В C переменные не должны использоваться в ярлыках case switch, вместо этого допускаются только постоянные выражения.

0
добавлено

На OSX, clang, кажется, принимает константы в качестве ярлыков случая без жалоб.

#include 

#define SOME_HARDCODED_CONSTANT 0 //good for sure
int foo(int i, int b){ 
    const int c=1; //no problem!!!

    switch(i){
        case SOME_HARDCODED_CONSTANT: //all good
            printf("case SOME_HARDCODED_CONSTANT\n"); break;
        case c:     //no compile error for clang
            printf("case c\n"); break;
        case 5: //all good
            printf("case 5\n"); break;
    }   
    return i+b;
}

int main() {
    printf("test foo(1,3): %d\n", foo(1,3));
}

Вывод:

$> cc test.c -o test; ./test 
case c
test foo(1,3): 4
0
добавлено
Он жалуется, если вы попросите его: caseconst.c: 10: 14: warning: выражение не является постоянным постоянным выражением; сворачивание его в константу является расширением GNU [-Wgnu-folding-constant] . Здесь const int c = 1; позволяет компилятору знать значение (как целочисленное константное выражение) во время компиляции, поэтому можно рассматривать c , как если бы это было целочисленное постоянное выражение в switch . Если вы инициализируете c вызовом функции, ожидайте ошибку компиляции.
добавлено автор Daniel Fischer, источник
Да, другая версия. Тем не менее, когда вы запрашиваете его придирчивость, он должен предупредить, -std = c11 -Weverything должен сообщить вам об этом, также -Wgnu-folding-constant , -pedantic-errors должны приводить к ошибке компиляции. Но поскольку это довольно безобидная вещь, вам нужно сказать, что компилятор действительно разборчив, прежде чем он упоминает об этом.
добавлено автор Daniel Fischer, источник
Да, поэтому компилятор только жалуется, когда вы его просите. Я хочу сказать, что это неправильный код по языковому стандарту, поэтому компилятор должен выдать диагностическое сообщение (при компиляции в режиме совместимости), даже если он принимает код (с которым нет ничего плохого). И хорошо, чтобы компилятор был придирчивым, поскольку это говорит вам о непереносимом коде, и вы можете принять обоснованное решение о том, сохраняете ли вы код или перезаписываете его для переносимости.
добавлено автор Daniel Fischer, источник
Вы можете использовать другую версию. Мой cc ничего не жалуется и сообщает версию следующим образом. $> cc --version $> Apple LLVM версия 6.0 (clang-600.0.57) (на основе LLVM 3.5svn) $> Цель: x86_64-apple-darwin14.3.0
добавлено автор Farley, источник
Придирчивая вещь не всегда необходима. Постоянное сгибание/распространение достаточно фундаментально для достойного компилятора, чтобы выяснить, является ли метка случая постоянным или нет независимо от деклараций. В этом случае предупреждение явно не обязательно по умолчанию с явными объявлениями констант, если только пользователи не попросят об этом.
добавлено автор Farley, источник