1. Си / Говнокод #5878

    +141

    1. 1
    2. 2
    3. 3
    unsigned b;
    unsigned char num;
    b = ((b & ((1 << num) - 1)) << ((sizeof(b) << 3) - num)) | (b >> num);

    Долго не мог понять, что оно делает.

    Запостил: movaxbx, 03 Марта 2011

    Комментарии (23) RSS

    • показать все, что скрытоЧто только люди не выдумывают, чтобы не изучать асм. Автору на мониторе написать ROR и бить головой об него до просветления.
      Ответить
      • Что за бред? Какой еще ассемблер? Ясно же сказано - программа на С.
        Ответить
        • автор как бе намекает нам что на асме это делается изящно и легко
          Ответить
    • учитывая неинициализированные переменные - всё что угодно.
      Ответить
    • Если аффтар хотел реализовать циклический сдвиг вправо, то делается это так

      b = (b << (CHAR_BIT * sizeof b - num)) | (b >> num);

      Видно, что общую идею он понимал. Но зачем он занимался каким-то дополнительным максированием в "левой" части (вот это вот `((1 << num) - 1)`) - не ясно. Говнокод, в общем.

      А замена умножения на сдвиг - говнокод втройне.
      Ответить
      • >А замена умножения на сдвиг - говнокод втройне.
        Это еще почему?
        Ответить
        • видимо, из-за магик-намберов, а нормальный компилятор умножать на 8 сам не будет.
          Ответить
          • да, действительно.
            >нормальный компилятор умножать на 8 сам не будет.
            я как-то об этом и не подумал
            Ответить
        • Хотя бы потому, что в таких тривиальных ситуациях, как умножение на константу времени компиляции, компилятор сам прекрасно разберется, как это сделать наиболее оптимальным образом. И, кстати, этот "наиболее оптимальный образ" уже сто лет как не сдвиг. На платформе x86 (например) умножение на константу уже давным давно делается через машинную команду `lea`, которая и будет наиболее оптимальным вариантом в данном случае.

          В такой ситуации заниматься идиотизмом и пытаться загнать компилятор "в сдвиг" - хрестоматийная классика говнокодирования.
          Ответить
          • не удержался и проверил:
            919 операций подряд без цикла (ну так накопировались инклуды). Нужно сделать eax = ecx * 8
            // 214000 раз в сек.
            mov eax, 8
            mul ecx
            // 260000 раз в сек.
            mov eax, ecx
            shl eax, 3
            // 226000 раз в сек.
            lea eax, [ecx * 8]

            машина HP Elitebook 8440p, XP SP3, оптимизации компилятора, понятное дело, отключены.
            Ответить
            • Подозреваю, что последний вариант должен неплохо параллелиться. В цикле-то обычно ещё и другие операции есть, занимающие ALU.
              Ответить
      • показать все, что скрытоЧтобы единички влево не сдвигать за границу. Мало ли что там за границей с этими единичками поизойдёт, как они по памяти начнут гулять.
        Ответить
        • никак не будут.
          а если шутка, то смайл ставьте:)
          Ответить
          • Я смайлики не пользую из принципа. Не люблю фильмы с закадровым смехом.
            Ответить
            • Лучше, наверное, вообще немые.
              Ответить
            • как угодно. только вот тут не сайт юмора. и шутку могут не отличить от фразы-заблуждения
              Ответить
              • Ну те, кто заблуждается в таких базовых вещах, тут не сидят.
                Ответить
          • Кстати, автор забыл обнулить биты справа, прежде чем делать >> num
            Надо было написать (b &!(1 << num - 1)) >> num
            Ответить
            • 1) Побитовая инверсия -- "~".
              2) Приоритет "-" выше, чем "<<".
              Ответить
              • 1) Блин, я забыл про этот костыль
                2) А вот это ещё одна хрень языка, я не знал про такую. Сдвиг же по функционалу схож с умножением/делением, которые более приоритетны, чем плюс/минус.
                Ответить
                • TarasB, что-то много костылей у тебя, в РЖД работаешь или в больнице. Больнице при РЖД?
                  Ответить

    Добавить комментарий