Несмотря на простоту (и, в общем-то, тривиальность, если подумать) описываемого решения, наткнулся на него чисто случайно, во время разукрашивания комментарием законченной программы, готовой к сдаче.

В программистской практике регулярно случается ситуация, когда на время разработки и отладки требуется включать какой-то код и выключать другой. Это несложно делать специальными конструкциями типа #if true ... #else ... #endif, меняя true на false, или прибегая к более изощренным условиям. Однако такая конструкция не позволяет создавать более двух альтернативных участков кода.

В языках, поддерживающих комментарий типа /* ... */ c помощью слегка нестандартной конструкции /**/ ... /*/ ... /*/ ... /**/ можно создавать сколько угодно чередующихся участков кода, которые будут попеременно включаться и выключаться одним лишь пробелом в первом (стартовом) из комментариев.

Например:

/**/
        Console.Write("1");
/*/
        Console.Write("2");
/*/
        Console.Write("3");
/*/
        Console.Write("4");
/**/
        Console.Write("5");

При выполнении этот код выведет в консоль строку "135". То есть, будут выполнены все нечетные операторы вывода — и последний, находящийся уже за пределами всей конструкции. Но если в стартовом комментарии между второй звездочкой и слешем вставить пробел (или, строго говоря, любой символ, кроме звездочки), то тот же самый код выведет строку "245": будут выполнены только четные операторы, и, опять же, последний, который уже за пределами. (UPD: благодарю FluffyMan за указание на ошибку).

Синтаксис комментариев-разделителей предельно строг: к конструкции /*/ ничего ни убавить, ни прибавить нельзя, это разрушит ее функционал. Синтаксис стартового и стопового комментария напротив совершенно произволен. Он может быть минималистичен до /**/, а может содержать какие угодно — легальные в смысле языка — комментарии. Откуда ясно, что стартовый и стоповый комментарии строго обязательны, и что внутри самой конструкции просто так использовать легальный комментарий типа /* ... */ нельзя, т.к. он тут же станет стоповым для всей предыдущей последовательности комментариев-разделителей /*/, и стартовым для всей последующей их последовательности. Но осмысленное использование таких вставок может оказаться полезным.

Однострочные комментарии // на функционал не влияют.

Dixi :)

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


  1. Gedweb
    25.12.2018 13:49
    +4

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


  1. AllexIn
    25.12.2018 13:50
    +4

    Краткое пособие «Как выстрелить себе в ногу на ровном вместе».

    UPD:
    Ну вот, мой остроумный коммент оказался мало того что не уникальным, так еще и не первым…


    1. pythe Автор
      25.12.2018 16:42
      -3

      Чем поддержка такого кода принципиально отличается от традиционного
      #define DEBUG
      #ifdef DEBUG

      #else

      #endif
      #ifdef DEBUG

      #else

      #endif
      ?


      1. iroln
        25.12.2018 16:49
        +1

        Тем, что комментарий надо искать и руками править, а DEBUG и любые другие дефайны можно конфигурировать на этапе конфигурирования/сборки, а также о них и их состоянии чаще всего знает ваша IDE. Это очевидно же.


        1. pythe Автор
          25.12.2018 17:04
          -2

          Понятно. Разумеется выключка комментированием предназначена исключительно для относительно «легких» текстов, и желательно IDE с подсветкой. Это верно для любой подобной техники. Но в «тяжелых» тоже попадалось.


  1. REPISOT
    25.12.2018 13:58
    +1

    #Ifdef в помощь


  1. acyp
    25.12.2018 14:02

    1. pythe Автор
      25.12.2018 16:31

      Не уловил логики… А, там тоже про комментарии? :)


      1. acyp
        25.12.2018 19:27

        Нет, про подход в решении. На ровном месте зарабатывать новые проблемы, примерно как в шутке про regexp. И это при том, что есть проверенные и тиражируемые методы.


  1. Vantela
    25.12.2018 14:18

    Я в школе делал так — создавал int DEBUG=1; и перед операторами которые нужны для дебага писал if(DEBUG){...}.

    Мой подход не идеален, но ваш ужасен.

    Переделывайте лучше на #ifdef. Пока не поздно.


  1. GennPen
    25.12.2018 14:18

    С такими комментариями потом бегай и ищи по коду что забыл включить/выключить.
    Нет уж, лучше по-старинке:
    #ifdef DEBUG
    #endif


  1. Bedal
    25.12.2018 14:21
    +2

    Эхх, вспоминается… М-222, ТА-1М. Программа прогонялась в один приём: загоняется колода перфокарт, транслируется и тут же выполняется. Получается единая распечатка кода программы и вслед за ним — результатов выполнения.
    Печаталось это на барабанном принтере, который интерпретировал CRLF как «очистить буфер»/«продвинуть бумагу на строку».
    Студенческая работа на алголе. пишем строку кода, потом слово comment, потом пробел и комментарий, очень похожий на код, но неправильный. Строка заканчивается нормальным crlf, ессно. Получив колоду перфокарт, отыскиваем нужный столбец и перевырезаем лезвием пробел на символ CR.
    Итого: на печати начальная часть строки и слово comment не появляются, так как буфер принтера очищен (cr). Зато неправильный код вот он, на печати, как родной.
    Сдаём в работу, получаем распечатку, несём преподавательнице.
    — Незачёт.
    — Почему?
    — У вас в программе грубые ошибки.
    — Не может быть, вот, ниже ведь результат. Он правильный?
    — Да, правильный. Но так быть не может.
    — Но вот же распечатка. Транслятор ошибок не выдал, программа выполнилась без ошибок и выдала правильные результаты — почему незачёт?
    — …
    было, развлекались пару раз…
    _________________
    Связь с постом — вроде бы понятная?


    1. pythe Автор
      25.12.2018 16:57

      Не очень :)) И как можно пробел (20) перерезать в CR (0D)?

      Лезвием дырки в перфокарте сверлить — мда, работа для ювелира-труженика :) Эх, времена… Я в немножко похожей ситуации пользовался автоматическим переносом слишком длинной строки. Принтеры были уже матричные.


      1. geher
        25.12.2018 19:17

        И как можно пробел (20) перерезать в CR (0D)?

        Зависит от кодировки перфокарт, а она была разная.
        В некоторых случаях пробел кодировался как раз отсутствием пробивок.
        В КПК-12 (иногда неправильно назывался ДКОИ-12, а 12 потому, что каждый символ кодировался пробивками или их остутствием в 12 строках) вроде оно невозможно (если не путаю), поскольку код пробела имел отверстие, которого не должно было быть в CR


        Лезвием дырки в перфокарте сверлить — мда, работа для ювелира-труженика

        Это да. У нас специальный пробойник имелся.


        1. yurrig
          26.12.2018 05:27

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


          1. Bedal
            26.12.2018 07:10

            именно так :-)

            пакетик с затычками
            который наполнялся, когда удавалось оказаться возле Бармалея (перфоратора перфокарт).


          1. geher
            26.12.2018 10:45

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


      1. Bedal
        26.12.2018 07:17

        пробел (20)

        ну, положим, не 20, а 40
        перерезать в CR (0D)?

        как и написал ув. yurrig, лишние дырки заклеивалась, нужные — прорезались. Одной дырочкой не обходилось.


        1. pythe Автор
          26.12.2018 10:41

          ну, положим, не 20, а 40

          Я там в hex выражался, а не в oct. Вспомнил позже, что да, пробелы были вообще без пробивок. А вот какими были коды CR ил LF не помню совсем.


          1. Bedal
            26.12.2018 10:55

            Я там в hex выражался, а не в oct
            уфф. Какой такой hex в М-222? Восьмерично-десятичные символы. И вообще, речь про перфокарты — со своим кодом. Кстати, точно уже не помню, в каких позициях что было. Больше 40 лет прошло, всё-таки. А подделывать гугленьем не хочу.


          1. geher
            26.12.2018 11:01

            Тут вам не ANSI. Так что именно 0х40 (ДКОИ-8).
            А пробел в разных перфокартных кодировках разным был.
            В КПК-12 пробел вроде был 12-9-8-5, а CR — 8-4 (могу путать, давно прошли времена, когда перфокарты по дырочкам мог читать).


  1. Capacitor10n
    25.12.2018 16:25

    Не более 2? Оо

    #define mode  0
    #if mode == 0
    #elif mode == 1
    #elif mode == 2
    ...
    #elif mode == 999999999
    #endif


    1. Keremet_2030
      26.12.2018 17:27

      Я иногда использую подход через case, делаю глобальную переменную DebugMode = n;
      case DebugMode of
      0: Begin
      //// код 1
      End;
      1: Begin
      //// Код 2
      End;
      2: Begin
      //// Код 3
      End;

      PS: Простите за паскаль


      1. GennPen
        26.12.2018 23:22

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


  1. FluffyMan
    25.12.2018 23:05

    Но если в стартовом комментарии между второй звездочкой и слешем вставить пробел

    может между звездочками? иначе тогда не понимаю как это работает.


    1. pythe Автор
      26.12.2018 09:53

      Оу, кажется, единственный комментатор, который обратил внимание на механизм :)

      Нет, пробел между звездочками ничего не изменит, именно перед слешем. Это превращает */ в * / и дезавуирует последовательность как завершающий комментарий токен. Таковым становится следующий в очереди /*/, который до этого наоборот начинал следующий блок комментария, и т.д. по цепочке до завершающего /**/. Лучше всего это наблюдать в IDE с подсветкой синтаксиса.


      1. FluffyMan
        26.12.2018 11:37

        Понял. Но тогда у Вас перепутано. Ведь этот код:

        /**/
                Console.Write("1");
        /*/
                Console.Write("2");
        /*/
                Console.Write("3");
        /*/
                Console.Write("4");
        /**/
                Console.Write("5");

        выведет 135, но после вставки пробела между звездочкой и слэшэм уже будет 245:

        /** /
        Console.Write("1");
        /*/
         Console.Write("2");
         /*/
        Console.Write("3");
        /*/
         Console.Write("4");
         /**/
        Console.Write("5");


        P.S. <source lang="cpp"> помог)

        Спасибо за разъяснение.


        1. Vantela
          26.12.2018 11:43

          Перепроверил в vi.

          Браво! Выходит автор выстрелил себе в ногу даже в статье в которой рассказывал как это сделать:)


          1. pythe Автор
            26.12.2018 17:40

            Выходит автор выстрелил себе в ногу даже в статье в которой рассказывал как это сделать:)

            :)))) Мда, выходит. Но заодно рикошетом зацепил целую кучу завсегдатаев гиков, которые из-за этого осерчали, и оказались не гиками, а нёрдами, и понаставили кучу минусов за несоответствие их идеалам. Вместо того, чтобы просто похихикать :)


            1. Vantela
              26.12.2018 17:47

              Я не ставил.:)

              Дело то не в идеалах.
              Реально ж очень легко запутаться где там пробел. Потому и заминусили статью.


              1. pythe Автор
                26.12.2018 18:00

                Да я ж не в претензиях :) Пусть их.

                Никто не мешает использовать вместо пробела строчку DEBUG — эффект будет точно тот же самый. Равно как никто не мешает вместо #define DEBUG использовать #define d и запутаться не меньше. Дело вкуса, а компилятору пофиг.


        1. pythe Автор
          26.12.2018 17:31

          Но тогда у Вас перепутано.

          Так точно. Этот самый попутал, который с рожками. Спасибо за поправку. Внесу Вашу коррекцию в текст.


  1. Andy_Big
    26.12.2018 14:09

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

    Директивами препроцессора (#ifdef, #if defined() и т.д.) можно создавать сколько угодно альтернативных участков кода. У меня, например, поддерживается около 18 вариантов одной программы. Причем во многих IDE можно создавать отдельные конфигурации построения под каждый вариант и построить все или выбранные варианты в несколько кликов мыши :)