operator break
Предлагаем вашему вниманию цикл статей, посвященных рекомендациям по написанию качественного кода на примере ошибок, найденных в проекте Chromium. Это вторая часть, которая будет посвящена оператору switch, а, вернее, проблеме забытого оператора break.

Многие годы я изучал ошибки в программах и сейчас могу с уверенностью заявить, что в C, а вслед за ним и в C++, оператор switch сделан неправильно. Я понимаю, что возможность не писать break, сделанная, чтобы передать управление дальше, позволяет писать изящные алгоритмы. Но всё равно огромное количество ошибок убедило меня, что был выбран неправильный подход. Понятно, что теперь уже поздно. Просто хотелось сказать, что правильным решением было бы обязательно писать слово break или обратное ключевое слово, например, fallthrough. Сколько бы сил, времени и денег было сэкономлено. Конечно, этот недостаток не сравнится с Null References: The Billion Dollar Mistake, но всё равно большой ляп.

Ладно, пофилософствовали и хватит. Язык C++ такой, какой есть. Однако, это не значит, что можно расслабиться и ничего не предпринимать для повышения качества и надёжности кода. Проблема «пропущенного break» — это большая проблема, и её нельзя недооценивать. Даже в высококачественном проекте Chromium прячутся ошибки этого типа.

Давайте посмотрим, что я заметил в процессе разбора отчета, выданного PVS-Studio. Как я писал в вводной статье, отчёт я смотрел достаточно бегло, поэтому могут быть и другие, незамеченные мной ошибки. Тем не менее, найденных ошибок мне будет достаточно, чтобы продемонстрировать, что всё это не отдельные случайные ляпы, а устойчивый паттерн ошибки. Читателям следует отнестись к этому паттерну серьезно и постараться использовать меры по его предотвращению.

Первая ошибка взята непосредственно из кода проекта Chromium.

int GetFieldTypeGroupMetric(....) {
  ....
  switch (AutofillType(field_type).group()) {
    ....
    case ADDRESS_HOME_LINE3:
      group = GROUP_ADDRESS_LINE_3;
      break;
    case ADDRESS_HOME_STREET_ADDRESS:
      group = GROUP_STREET_ADDRESS;
    case ADDRESS_HOME_CITY:
      group = GROUP_ADDRESS_CITY;
      break;
    case ADDRESS_HOME_STATE:
      group = GROUP_ADDRESS_STATE;
      break;
    ....
}

Независимо от того, нужно ли автоматически заполнить некое поле «Street Address», или поле «Сity», в любом случае будет выбрана константа GROUP_ADDRESS_CITY. Т.е. где-то вместо названия улицы автоматически будет подставляться название города.

Причина в том, что пропущен оператор break. В результате, после присваивания:

group = GROUP_STREET_ADDRESS;

Переменной group тут же будет присвоено новое значение:

group = GROUP_ADDRESS_CITY;

Анализатор PVS-Studio замечает это двойное присваивание и выдаёт предупреждение: V519 The 'group' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 145, 147. autofill_metrics.cc 147

Вторая ошибка также относится к коду Chromium и выглядит схожим образом.

void GLES2Util::GetColorFormatComponentSizes(...., int* a) {
  ....
  // Sized formats.
  switch (internal_format) {
    case GL_ALPHA8_EXT:
      *a = 8;
    case GL_ALPHA16F_EXT:
      *a = 16;
    case GL_ALPHA32F_EXT:
      *a = 32;
    case GL_RGB8_OES:
    case GL_SRGB8:
    case GL_RGB8_SNORM:
    case GL_RGB8UI:
    case GL_RGB8I:
      *r = 8;
      *g = 8;
      *b = 8;
      break;
    case GL_RGB565:
  ....
}

Здесь забыто 2 или 3 оператора break. Я не знаю, как точно должен работать этот код, поэтому воздержусь от комментариев по поводу того, как следует исправить ошибку. Анализатор PVS-Studio выдаёт для этого кода два предупреждения:
  • V519 CWE-563 The '* a' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1385, 1387. gles2_cmd_utils.cc 1387
  • V519 CWE-563 The '* a' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1387, 1389. gles2_cmd_utils.cc 1389

Третья ошибка из кода Chromium.

gfx::ColorSpace VideoColorSpace::ToGfxColorSpace() const {
  ....
  switch (primaries) {
  ....
  case PrimaryID::SMPTEST431_2:
    primary_id = gfx::ColorSpace::PrimaryID::SMPTEST431_2;
    break;
  case PrimaryID::SMPTEST432_1:
    primary_id = gfx::ColorSpace::PrimaryID::SMPTEST432_1;
  case PrimaryID::EBU_3213_E:
    primary_id = gfx::ColorSpace::PrimaryID::INVALID;
    break;
  }
  ....
}

Точно та же картина, что и раньше. Предупреждение PVS-Studio: V519 CWE-563 The 'primary_id' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 106, 109. video_color_space.cc 109

Четвёртая ошибка из кода Chromium. В этот раз нам уже поможет предупреждение V796, а не V519. Диагностика V519 выявляет пропущенный break косвенным образом, когда замечает повторное присваивание. Диагностика V796 разработана специально для поиска пропущенных операторов break.

void RecordContextLost(ContextType type,
                       CommandBufferContextLostReason reason) {
  switch (type) {
    ....
    case MEDIA_CONTEXT:
      UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.Media",
        reason, CONTEXT_LOST_REASON_MAX_ENUM);
      break;
    case MUS_CLIENT_CONTEXT:
      UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.MusClient",
        reason, CONTEXT_LOST_REASON_MAX_ENUM);
      break;
    case UI_COMPOSITOR_CONTEXT:
      UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.UICompositor",
        reason, CONTEXT_LOST_REASON_MAX_ENUM);
    case CONTEXT_TYPE_UNKNOWN:
      UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.Unknown",
        reason, CONTEXT_LOST_REASON_MAX_ENUM);
      break;
  }
}

После выполнения ветки «UI_COMPOSITOR_CONTEXT» управление передаётся в ветку «CONTEXT_TYPE_UNKNOWN». По всей видимости, это приводит где-то к неверной обработке… А вот не знаю я, на что это повлияет. Но break здесь пропущен, по всей видимости, случайно, а не намеренно.

Предупреждение PVS-Studio: V796 CWE-484 It is possible that 'break' statement is missing in switch statement. command_buffer_metrics.cc 125

Пятая ошибка в коде Chromium, из-за которой страдает средняя клавиша мыши.

void SystemInputInjectorMus::InjectMouseButton(
  ui::EventFlags button, bool down)
{
  ....
  int modifier = ui::MODIFIER_NONE;
  switch (button) {
    case ui::EF_LEFT_MOUSE_BUTTON:
      modifier = ui::MODIFIER_LEFT_MOUSE_BUTTON;
      break;
    case ui::EF_RIGHT_MOUSE_BUTTON:
      modifier = ui::MODIFIER_RIGHT_MOUSE_BUTTON;
      break;
    case ui::EF_MIDDLE_MOUSE_BUTTON:
      modifier = ui::MODIFIER_MIDDLE_MOUSE_BUTTON;
    default:
      LOG(WARNING) << "Invalid flag: " << button
                   << " for the button parameter";
      return;
  }
  ....
}

Неправильно обрабатывается нажатие на среднюю клавишу мыши. После корректного действия:

modifier = ui::MODIFIER_MIDDLE_MOUSE_BUTTON;

Происходит переход к обработчику ошибочных флагов, и функция досрочно завершает свою работу.

Предупреждение PVS-Studio: V796 CWE-484 It is possible that 'break' statement is missing in switch statement. system_input_injector_mus.cc 78

Здесь читатель вправе сказать: «Всё понятно, достаточно!». Однако, мне попалась на глаза ещё парочка таких ошибок в используемых библиотеках, так что давайте посмотрим и на них. Я хочу убедительно показать, что этот вид ошибок повсеместен.

Шестая ошибка живёт в коде библиотеки Angle, используемой в Chromium.

void State::getIntegerv(const Context *context,
                        GLenum pname, GLint *params)
{
  ....
  switch (pname)
  {
    ....
    case GL_DEBUG_GROUP_STACK_DEPTH:
      *params = static_cast<GLint>(mDebug.getGroupStackDepth());
       break;
    case GL_MULTISAMPLE_EXT:
      *params = static_cast<GLint>(mMultiSampling);
       break;
    case GL_SAMPLE_ALPHA_TO_ONE_EXT:
      *params = static_cast<GLint>(mSampleAlphaToOne);      // <=
    case GL_COVERAGE_MODULATION_CHROMIUM:
      *params = static_cast<GLint>(mCoverageModulation);
       break;
    case GL_ATOMIC_COUNTER_BUFFER_BINDING:
    ....
}

Предупреждение PVS-Studio: V519 CWE-563 The '* params' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 2044, 2046. state.cpp 2046

Седьмая ошибка живёт в коде библиотеки SwiftShader, используемой в Chromium.

GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer(....)
{
  ....
  switch(target)
  {
  case GL_DRAW_FRAMEBUFFER:
  case GL_FRAMEBUFFER:
    framebuffer = context->getDrawFramebuffer();
  case GL_READ_FRAMEBUFFER:
    framebuffer = context->getReadFramebuffer();
    break;
  default:
    return error(GL_INVALID_ENUM);
  }
  ....
}

Предупреждение PVS-Studio: V519 CWE-563 The 'framebuffer' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 3879, 3881. libglesv3.cpp 3881

Семь — это красивое число. На нём и остановимся. Возможно, есть другие ошибки, но их поиск я оставляю авторам Chromium и библиотек. Мне было скучно внимательно смотреть предупреждения V519. Диагностика V519 даёт немало бестолковых ложных срабатываний, связанных с неаккуратным написанием кода или с макросами. А настраивать анализатор для такого большого проекта – это уже работа, требующая оплаты (да, это был тонкий намёк для Google).

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

Рекомендация

Как я написал в начале, по моему мнению, причина подобных ошибок в неудачной реализации синтаксиса языка. И что-то менять уже поздно. Однако, постепенно эту проблему решают компиляторы и анализаторы. Уже давно существуют предупреждения, сообщающие о том, что забыт оператор break. А когда действительно надо передать управление дальше, то компиляторам и анализаторам сообщают об этом с помощью специальных магических заклинаний, таких как:
  • [[gnu::fallthrough]];
  • [[clang::fallthrough]];
  • __attribute__((fallthrough));
  • BOOST_FALLTHROUGH;
  • и так далее.

К сожалению, всё это было как-то не универсально. К счастью, у меня для всех C++ программистов есть хорошая новость. В стандарте C++17 наконец утвердили стандартный метод подсказать компилятору, что программист специально планирует передать управление дальше. Это атрибут [[fallthrough]]. Анализаторы, естественно, тоже будут пользоваться этой подсказкой. Кстати, рекомендую посмотреть нашу статью "C++17" про то, что нового появилось в этом стандарте.

Чуть подробнее про атрибут [[fallthrough]].

Этот атрибут показывает, что оператор break внутри блока case отсутствует намеренно (т.е. управление передается в следующий блок case), и поэтому соответствующее предупреждение компилятора или статического анализатора кода выдаваться не должно.

Пример использования:

switch (i)
{
case 10:
  f1();
  break;
case 20:
  f2();
  [[fallthrough]]; // Предупреждение будет подавлено
case 30:
  f3();
  break;
case 40:
  f4();
  break;
}

Если Вы уже перешли на C++17, нет причин не использовать [[fallthrough]]. Включите предупреждения в своём компиляторе, чтобы он информировал о пропущенном break. А там, где оператор break в действительности не нужен, пишите [[fallthrough]]. Также рекомендую описать всё это в используемом в вашей компании стандарте кодирования.

Компиляторы Clang и GCC начинают предупреждать о пропущенном break, если указать им флаг:

-Wimplicit-fallthrough

Если добавить [[fallthrough]], то предупреждение пропадает.

С MSVC сложнее. Начиная с Visual C++ 2017 RTM, он, вроде, должен выводить предупреждение C4468, если указан флаг /W4. Подробнее: Compiler Warnings by compiler version (см. C4468). Но что-то у меня последняя версия Visual Studio со всеми последними обновлениями упорно молчит. Впрочем, я долго не экспериментировал и, возможно, сделал что-то неправильно. В любом случае, если не сейчас, то в ближайшее время этот механизм будет работать и в Visual C++.

Спасибо всем за внимание. Желаю всем безбажного кода. Да, и не забудьте попробовать проверить с помощью PVS-Studio ваши рабочие проекты.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. break and fallthrough.

Комментарии (33)


  1. CDK
    27.01.2018 16:15

    У меня глупый вопрос — а сама VS (или тот компилятор, что используют авторы Хромиума) на:

      case PrimaryID::SMPTEST432_1:
        primary_id = gfx::ColorSpace::PrimaryID::SMPTEST432_1;
      case PrimaryID::EBU_3213_E:
        primary_id = gfx::ColorSpace::PrimaryID::INVALID;
        break;

    не выдает варнинга типа: value assigned to primary_id never used…?
    (я очень редко влезаю в C/CPP, поэтому сам не знаю)


    1. Andrey2008 Автор
      27.01.2018 16:19
      +1

      Теперь выдаёт :)

      Comment 1.

      Add a FALLTHROUGH macro and get base/ to build with -Wimplicit-fallthrough.

      Also fix a few missing breaks found by the warning in gpu/.


  1. CDK
    27.01.2018 16:24

    Не, я про саму Visual Studio (или я не так Вас понял?). Просто дельфятник в таком случае напишет подобное сам, т.к. в
    primary_id = gfx::ColorSpace::PrimaryID::SMPTEST432_1;
    значение присвоенное primary_id не используется — его сразу же переназначают.
    Я это к тому, что, похоже, авторы Хромиума игнорируют варнинги компилятора.
    PS: промахнулся с веткой :(


    1. Andrey2008 Автор
      27.01.2018 16:40

      Компиляторы по умолчанию ничего не сообщают, так как отсутствие break это изначальная фишка языка. В двойном присваивании одной переменной тоже ничего особенного нет. Так очень часто пишут. Поэтому в диагностике V519, выявляющей повторное присваивание, есть множество различных исключений.

      И я имел в виду, что раньше не использовался ключ, -Wimplicit-fallthrough (про него, кстати, говорится в статье). А теперь используется, что видно из общения в багтрекере разработчиков Chromium.

      Двойные присваивания искать — дело совсем неблагодарное. Нужен умный инструмент, такой как PVS-Studio, чтобы снижать шум.


  1. datacompboy
    27.01.2018 17:32
    +5

    ооо мои глаза… никакие ревью от таких ошибок не защитят 8(


    1. Andrey2008 Автор
      27.01.2018 17:40
      +6

  1. Tangeman
    27.01.2018 19:24
    -2

    Любой язык программирования и его возможности — это всего лишь инструмент. Его неправильное использование (сознательно или в силу отсутствия опыта или знаний) — проблема того кто использует, а не проблема языка.

    Эдак можно дойти до утверждения в духе «молотки сделаны неправильно — ими можно ударить по пальцу или убить кого-нибудь».

    Именно по этой причине в мире «железных» вещей существуют правила, инструкции и техника безопасности, а при необходимости — те, кто следит за их исполнением, и которые наказывают нарушителей.

    Мне кажется более логичным не ограничивать языки, а совершенствовать тех, кто их испольузет — прямо (обучение + опыт) или косвенно (статический + динамический анализы).

    PS: Если бы у средств типа PVS-Studio была более либеральная ценовая политика, вероятно, это сильно бы улучшило качество кода и уменьшило количество ошибок для массы программистов. Большинство разработчиков, особенно в open source, не могут себе позволить платить $60/мес, в то время как действительно опытные разработчики в таких средствах не нуждаются вовсе.


    1. Dim0v
      27.01.2018 19:44
      +2

      действительно опытные разработчики в таких средствах не нуждаются вовсе.

      Спорно. Даже самый опытный гуру может отвлечься/задуматься не о том/опечататься и т.д. и в результате получить в коде какую-то дичь. И далеко не всегда эта дичь вылезет сразу. Может оставаться в коде месяцами и годами.


      1. Tangeman
        27.01.2018 20:18
        -2

        Если этот гуру в единственном экземпляре — да. Если их несколько — то review кода уставшего/неспавшего гуру тем кто уже успел отдохнуть решает проблему, как правило. Главным условием является то что все гуру заняты одним проектом.


        1. aamonster
          27.01.2018 20:41

          "Никогда не посылай человека туда, куда можно послать пулю" © Джеймс Бонд.
          Зачем тратить время гуру на то, что можно проверить автоматически?


          1. Tangeman
            27.01.2018 20:56

            Пока автоматика не настолько совершенна, а ложное чувство что она увидит всё приводит к более серьезным проблемам (автопилот теслы тому пример).

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


            1. aamonster
              27.01.2018 21:40

              Вот в том-то и дело, что "рано списывать гуру". У него очень много дел, и не стоит загружать его ерундой.


              Вообще сколько лет пишу на C и C++ — столько с тоской вспоминаю Паскаль каждый раз, как мне надо написать switch-case. 95% всех случаев "fallthrough" покрывались банальным перечислением констант через запятую или прописыванием диапазонов.


              Ну и, опять же, если вернуться к аналогии с молотками — вариант с [[fallthrough]] не мешает вам ковырять молотком в носу, а лишь спрашивает вас — "вы действительно хотите это сделать"?.. По моему, хорошо. А вариант с оператором fallthrough вместо break — требует явно указывать "здесь ковырять в носу", зато избавляет от необходимости писать break каждый раз, как вам надо забить гвоздь.


    1. Andrey2008 Автор
      27.01.2018 19:44
      +1

      Руководствуясь приведённой логикой, не следует развивать Spelling & Grammar чекер в Microsoft Office, лучше учить детей в школе языку. Лучше? Лучше. И что дальше?

      В общем, подобные рассуждения не имеют практического смысла. Только наша команда нашла в Open Source проектах уже 13483 ошибки. Причём у нас никогда не было цели найти как можно больше ошибок и это просто побочны продукт процесса написания статей. Думаю, общее количество ошибок, которые исправлены благодаря нашему инструменту, исчисляется сотнями тысяч. Можно рассуждать теоретически о том, как сделать мир лучше и как сделать, чтобы программисты не ошибались. Но вот только всё равно они ошибаются и найденные нами ошибки это подтверждают. Поэтому использование PVS-Studio это практический шаг по улучшению качества и надёжности кода. А философию мы оставляем философам :)

      Большинство разработчиков, особенно в open source, не могут себе позволить платить $60/мес, в то время как действительно опытные разработчики в таких средствах не нуждаются вовсе.
      Как раз всё наоборот. Многим разработчикам open source приложений в инструментах статического анализа не нуждаются. В маленьких проектах низкая плотность ошибок и нет старого унаследованного кода, который никто не знает. Ну или на крайний случай можно воспользоваться бесплатным вариантом PVS-Studio. Зато этот инструмент нужен и полезен профессиональным разработчикам и компания может позволить им его купить.


      1. Tangeman
        27.01.2018 20:13
        -1

        Руководствуясь приведённой логикой, не следует развивать Spelling & Grammar чекер в Microsoft Office, лучше учить детей в школе языку. Лучше? Лучше. И что дальше?

        Я этого не говорил. Если применить вашу логику к данной аналогии — то нужно запретить Microsoft Office писать в документах слова с ошибками (ну или сохранять их) — а это уже зверство. Предупредить, направить — да, но последнее слово должно оставаться за автором.

        Spelling / Grammar checker как раз нужны — ибо они помогают совершенствоваться.

        Поэтому использование PVS-Studio это практический шаг по улучшению качества и надёжности кода.

        Простите, но именно это я и сказал — если вы внимательно вчитаетесь :) Я просто против «внедрения» правил в сами языки (особенно если их нельзя обойти).

        Зато этот инструмент нужен и полезен профессиональным разработчикам и компания может позволить им его купить.

        Не все работают на компании, и не все зарабатывают кодом — но как раз именно они и «производят» больше всего ошибок.

        Именно это и является большой проблемой, на мой взгляд — непрофессионалы пишут что-то полезное (и оно даже работает), но делают это «как умеют», т.е. с типичными проблемами, потом другие (уже включая профессионалов с небольшим опытом) копипастят их творения и множат проблемы. Иногда после разбора ответов на Stack Overflow волосы дыбом встают, но факт остается фактом — ответ который выполняет задачу принимается как «лучший», даже несмотря на наличие в нём потенциальных проблем, а дальше по спирали.

        Но, поскольку эти самые непрофессионалы редко зарабатывают своим кодом, они вряд-ли подпишутся на такой тулз который стоит в общем-то, немало (даже весь комплект всего для разработчиков от JetBrains стоит дешевле, и он, кстати, включает в себя элементы статического анализа, а в Visual Studio это входит вообще даром — но не все могут им пользоваться).


        1. creker
          28.01.2018 13:39
          +2

          Я просто против «внедрения» правил в сами языки (особенно если их нельзя обойти).

          Языки программирования это одни сплошные правила, которые нельзя обойти. Вам всего лишь не нравится какое-то из них. Но даже если так, какое это имеет отношение к break и fallthrough? Это не ограничение, все возможности на месте, только теперь предотвращена очень распространенная ошибка.


    1. gnomeby
      27.01.2018 19:55
      +1

      Аналогия некорректная. Молотками пользуются не все. А вот конструкциями switch все. А убить — осознанное действие. Удар по пальцам сразу заметен и поведение корректируется, а вот забыть break — типичная ошибка и невнимательность, которая будет жить долго.


      1. Tangeman
        27.01.2018 20:32

        Я считаю аналогию корректной по одной простой причине — несмотря на то что многие отбили себе пальцы, и не менее многие знают что можно отбить себе пальцы, всё же отбивание пальцев искоренить не удаётся (причём достаточно тех, кто делает это не один раз), но в то же время те кто свято соблюдает правила ТБ, ничего себе не отбивают — и прошу заметить, это не требует модификации молотков. А убить можно и случайно — если размахнуться молотком в момент когда кто-то стоит на траектории замаха.

        К тому же, я уверен что молотками пользуется гораздо больше людей чем тех кто пользуется switch :)


        1. AllexIn
          28.01.2018 07:01
          +3

          Речь не идет о запрете некой возможности.
          Речь идет о том, что по ошибке решили, что чаще будет использоваться одна конструкция, но в итоге оказалось, что она и нужна редко и приводит к куче ошибок. Всё что надо — перевернуть ситуацию. Где вы тут запрет увидели — совершенно не понятно.


    1. DrLivesey
      28.01.2018 09:47
      +3

      Любой язык программирования и его возможности — это всего лишь инструмент.

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


      Моя личная позиция по этому поводу: если можно сделать язык безопаснее на уровне базовых концепций — это должно быть сделано.


  1. Andrey2008 Автор
    27.01.2018 19:43

    (del)


  1. crea7or
    27.01.2018 19:47
    +1

    Чувакам в хромимум пишет пулреквесты кто-нибудь по этим ошибкам? Или посабмитить в свободное время? (Это не к автору поста вопрос)



  1. GreedyIvan
    28.01.2018 10:12
    -3

    А где во втором примере ошибка? Или последовательность if без else для проверки одной и той же переменной — это тоже ошибка?


    1. Andrey2008 Автор
      28.01.2018 10:14

      Э… Что?


    1. DukeKan
      28.01.2018 11:22
      -3

      Судя по названию переменных, там может быть всё правильно. Но вот коммента в коде, о том что так и задумывалось не хватает


    1. mayorovp
      28.01.2018 11:49
      +1

      Как где? В случае GL_ALPHA8_EXT будут последовательно выполнены *a=8; *a=16; *a=32;, что не имеет смысла.


      А где вы там if и else нашли?


      1. GreedyIvan
        28.01.2018 13:34
        -2

        If без else — это аналогия. Но тут больше вопрос, с чего вдруг при GL_ALPHA8_EXT будут выполняться другие кейсы, отличные от default?


        1. Andrey2008 Автор
          28.01.2018 13:39
          +1

          1. GreedyIvan
            28.01.2018 13:52
            -2

            Да, вы правы. В C и унаследованных от него языков используется аналог дерева, т.е. переход осуществляется по первому сработавщему условию. Остальные условия игнорируются, так как являются не частью кода, а точками входа в код.


            1. creker
              28.01.2018 14:22
              +2

              Это таки интересные вбросы у вас или что? В данный момент я скорее озадачен.


              1. GreedyIvan
                28.01.2018 14:32

                Всё просто. Я попутал. Swich-case действительно работает так, что там ошибка, так как внутри оператора switch пишется код, выполнение которого прерывается оператором break. А метки case используются как точки входа в этот код.


  1. datacompboy
    28.01.2018 12:27
    +1

    Это просто расчудесно и прямо в тему!!!
    turnoff.us/geek/the-last-resort


    ответ тут


  1. netch80
    28.01.2018 18:20

    Не упомянут ещё один вариант пометки — применявшийся для классического lint: /* FALLTHROUGH */ или /* FALLTHRU */. Во многих исходниках на C/C++ он используется до сих пор. Там принимается ещё десяток опций — проверка стиля printf, использование аргументов и т.п. К сожалению, новые анализаторы не используют эти директивы (не знаю ни одного), а lint не умеет C++ или C99, поэтому такие директивы в новом коде не пишут — но ещё полно старого.
    Рекомендую определять их наравне с новыми средствами в духе этого C++17.