Препроцессор C, выпрыгивающий из #ifdef

В настоящее время я изучаю C, и я столкнулся с этим вопросом, на который не могу найти ответ.

Могу ли я выйти из #ifdef, не проходя через #endif?
Например, я могу сделать это:

   char getOS( void ) {
       /* Returns the user Operating System
       */

       #ifdef _WIN32
           return 'w';

       #elif TARGET_OS_MAC
           return 'm';

       #elif __linux__
           return 'l';

       #else
           raiseError( "You cannot play on this OS", true );

       #endif

   }

Добавьте (например) return 0; после raiseError, чтобы все пути использовали возврат char. В противном случае ваш код в порядке.

Craig Estey 16.11.2022 21:54

Что вы подразумеваете под "выпрыгнуть из"? В цепочке #if...#elif...#else будет выбран только один.

dbush 16.11.2022 21:58
cpp условные операторы (например, #ifdef, #elif) не похожи на операторы C if. Они не генерируют все возможности, как if. Код #ifdef «выбирает» на первом этапе компиляции. Итак, если _WIN32 определено, более поздние этапы компиляции будут видеть [только]: char getOS( void ) { return 'w'; } и компилировать это. Вы можете заменить raiseError( "You cannot play on this OS", true ); на #error You cannot play on this OS, чтобы компиляция не удалась, если вы компилируете в неподдерживаемой системе.
Craig Estey 16.11.2022 22:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
52
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я считаю, что вы немного неправильно понимаете препроцессор. Помните, препроцессор запускается перед компилятором. Таким образом, эта функция будет выглядеть примерно так, когда попадет в компилятор:

char getOS( void ) {
        return 'w';
}
char getOS( void ) {
        return 'm';
}
char getOS( void ) {
        return 'l';
}
char getOS( void ) {
        raiseError( "You cannot play on this OS", true );
}

... и все они действительны. Ну, я не знаю, что делает raiseError, но если это не макрос, который returns или exits, вам нужно будет добавить дополнительный return в конец функции для ветки #else.

Дело в том, что ни один из этих #if, #elif и т. д. все равно не попадет в компилятор, поэтому вы никогда не «выскакиваете». Если вы хотите убедиться сами, вы можете добавить параметр компилятора, чтобы выполнять только предварительную обработку (без компиляции). Я знаю, что для gcc этот вариант -E.

Большое тебе спасибо. Наконец-то я понимаю, что на самом деле делает препроцессор

isGonzito 16.11.2022 23:31

Кажется, вы путаете препроцессор с поведением во время выполнения: это не одно и то же.

Препроцессор запускается до фактического компилятора (по крайней мере, концептуально; на практике, конечно, это может быть одна и та же программа). Это влияет на источник, который затем видит компилятор.

Вы не можете «пройти» #endif, его нет, когда программа работает. У вас будет либо return, либо звонок raiseError().

И тебе спасибо. Теперь я наконец понял :)

isGonzito 16.11.2022 23:36

Если под «выпрыгнуть из» вы подразумеваете, что компилятор выдаст ошибку, вы можете сделать это с помощью директивы #error.

   #ifdef _WIN32
       return 'w';

   #elif TARGET_OS_MAC
       return 'm';

   #elif __linux__
       return 'l';

   #else
       #error "You cannot play on this OS"

   #endif

Под «выпрыгнуть из» я имел в виду, что если бы первое условие было истинным, я бы никогда не достиг #endif, и я подумал, что это может быть проблемой. Теперь я лучше понимаю, что на самом деле делает препроцессор. Ваше решение все еще полезно. Спасибо :)

isGonzito 16.11.2022 23:28

Другие вопросы по теме