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

    +132

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    #define LengthOfArrayInternal(a)(sizeof(a)/sizeof(a[0]))
     
    #define is_array(x) _Generic((x), typeof((x)[0])[LengthOfArrayInternal(x)]:1, default: 0)
     
    #define COMPILE_TIME_ASSERT(expr) char constraint[expr]
     
    #define length_of_array(a) ({COMPILE_TIME_ASSERT(is_array(a)); LengthOfArrayInternal(a)})

    Определение длины массива. gcc и с11 only.
    Говно как известно рождается в споре:
    http://govnokod.ru/12108#comment160631

    Запостил: LispGovno, 15 Ноября 2012

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

    • с11 компилятора у меня нет, так что ещё нужно проверить
      Ответить
    • Странно. А я уж подумал - неужели?
      Неужели день прошел без того, чтобы Гумно не запостило очередной херни.
      Ответить
      • ты так говоришь, как будто у тебя есть реализация понадежнее или покороче, не считая заведения отдельной константы под длину
        Ответить
        • Ты так говоришь, как-будто это нужно.

          Знать длину массива и при этом не заводить константу под нее нужно только в одном случае - инициализированный массив неизвестной длины:
          int s[] = {1,2,3,4,5};
          А этих случаев во-первых не так много, во-вторых если он все-таки будет перепилен на указатель, тебе все равно придется где-то хранить длину, и втыкать ее вместо sizeof().
          Ответить
          • >Ты так говоришь, как-будто это нужно.
            В соседнем треде
            http://govnokod.ru/12108#comment160879
            , из которого вырос этот тред, сказали, что создатели google chrome используют плохоработающий COUNT_OF. Скажи это им.
            Ответить
            • Вот такая штука еще сегодня попалась:
              (void*)&(a) == (void*)(a)
              Для массива &a и a равны, а у всех остальных типов нет. Проверка надежная, но, к сожалению, в райнтайме.

              http://ideone.com/N9FpVB
              Ответить
              • Интересный способ. Уж лучше чем ничего. Интересно, а в крестах это соблюдается? Пока вижу несоблюдение этого правила только при перегрузке оператора взятия адреса.
                Ответить
              • интересно, а можно ли реализовать это функцией, а не макросом?
                и, кстати, если значение переменной совпадает с адресом, это может быть и не массив, а случайное совпадение :)
                http://ideone.com/WPiT43
                Ответить
            • Проверка во время компиляции: http://ideone.com/5sJmTR.

              Тестил на gcc с -Wall -Wextra -pedantic -std=c89 и до кучи на -ansi, поэтому скорее всего должно заработать и на визуалке и других компиляторах.

              P.S. В режиме с++ этот макрос использовать нельзя.
              P.P.S. В хидерах тоже использовать нельзя. Если очень хочется - нужно __LINE__ поменять на __COUNTER__, который не кроссплатформа.
              Ответить
              • В компил-тайме оно работает, только вот не впихнуть его в макрос length_of_array из-за того, что это declaration, как я писал ниже. :(
                Ответить
                • Да по-нормальному походу никак. Кроме как гццизмом с блоками внутри выражений.

                  P.S. Разве что найти какую-то хрень, которая не будет компилиться внутри выражений в зависимости от какого-то параметра...
                  Ответить
                  • http://ideone.com/X3iqLh
                    Первое, что приходит в голову - ошибка компиляции при преобразовании типов, но как заставить макрос в зависимости от условия вернуть переменную нужного типа?

                    upd: А впрочем я кажется знаю.
                    Ответить
                    • Нет, я не знаю и убежден, что это не возможно. :(
                      Ответить
                      • http://ideone.com/HRGzcL
                        http://ideone.com/N7MZ4R

                        За неимением лучшего.
                        Ответить
                        • Не, не так:
                          http://ideone.com/j2dVoo
                          Ответить
                          • Хотя действительно за неимением лучшего...
                            Ответить
                        • На самом деле плюс length_of_array в том, что он выдает длину массива времни компиляции, например:
                          http://ideone.com/grht3g
                          К сожалению эта реализация это не делает. Можно конечно энум использовать для взврата значения, но тогда она не сможет выдавать длину массива времени выполнения.
                          Ответить
    • _Generic - c11
      typeof и statement in expression - gcc extension
      Ответить
    • Ох уж эти крестолюбы-псевдофункциональщики...
      Сишка - отличный язык. Да, компилятор делает для тебя не так много работы, зато язык по большей части очень прост и не перегружен абстракциями и парадигмами.
      Он для людей, которые решают задачи, а не школьников, которые хвалятся на геймдеве очередным крестовысером.

      Хотя и кресты можно использовать правильно, если подойти к этому с головой.
      Ответить
      • Почему меня уже в крестолюбы записали, лол? Я самый настоящий функциональщик.
        Ответить
        • Крестопримеры кидал - кидал. Значит крестолюб.
          Ответить
          • Ну и ты зашквариться успел крестопримерами.
            Видать тоже крестолюб.
            Ответить
            • > Видать тоже крестолюб.
              А я этого и не отрицал.
              Ответить
            • Это ничего не значит. Я вот сколько крестопроблем повидал, а в крестолюбии меня обвинить трудно.
              Ответить
          • >Крестопримеры кидал - кидал.
            Я за всю жизнь не то что-бы кинуть, даже случайно уронить флешку с крестопримером не смог. А ты говоришь кидал.
            Ответить
        • истинно говорю тебе - трижды отречешься от крестов, прежде чем прокукарекает петушок
          Ответить
      • А я считаю, в сишку пора уже нормально добавить рантйам в компилятор.
        Например
        #define fACT(x) _Do
        {
          if (_Isconst(x)) 
          {
            int r=x; while(--x) r*=x;
            _Generate("$r");       
          } else _Generate ("int r=x; while(--x) r*=x; return x;");
        }
        Ответить
        • Если честно лучше не надо. Здесь оно выглядит как ослу пятая нога. Так получится "Паладин 2".
          Ответить
          • Если честно, то сишка - лучший кандидат (после лоловэма) на добавление рантайма в компилятор. Потому что нет ничего лишнего, всё, что нужно, можно добавить средствами языка, правда, с уёбищным синтаксисом и полным отсутствием поддержки со стороны среды.
            Ответить
            • Рантайм современной сишки так разбух. Там помоему в gcc сейчас даже рантайм крестов в сишку пихают. Поэтому не взлетит.
              Ответить
              • > Там помоему в gcc сейчас даже рантайм крестов в сишку пихают.
                Да ну. Если не изменяет память можно вообще libc отстегнуть и писать на голых syscall'ах/winapi.

                А рантайм крестов в гцц это libstdc++, по дефолту он не пристегивается.
                Ответить
                • Ну ты померь размер программы на сишке gcc и на крестах gcc. И сравни размер сишной программы на gcc там какого-нибудь мохнатого года и современную сишную на gcc. Разрослось, врагу не пожелаешь.
                  Ответить
                  • Какое это имеет отношение к теме разговора.
                    Ответить
                    • А такое, что писать рантайм для языка на языки с большим рантаймом - моветон. Смотри компилятор D, например.
                      Ответить
                      • Я не про то, чтобы добавить что-то в рантайм сишки, а наоборот, добавить рантайм в компилятор. Гумно, ты опять отвечаешь невпопад?
                        Ответить
                        • А ты опять спрашиваешь не в поп ад? Соберись. Подумай немного. Я верю в тебя.
                          Ответить
              • Я не про то, чтобы добавить что-то в рантайм сишки, а наоборот, добавить рантайм в компилятор. Гумно, ты опять отвечаешь невпопад?
                Ответить
                • Я про тоже самое. Ну а если ты "не понял юмора" (см пост ниже), то я ничего не могу c тобой поделать. Все вопросы к своим родителям и учителям.
                  Ответить
            • Ну и по моему лолиВм более лоли. По этому подходит больше.
              Ответить
        • Лол точка с запятой и до конца строки зелёные, мой код что, приняли за асм?
          Ответить
    • Кстати, может кто видит, как избавится от gcc extension statement and declaration in expression? Мне пришлось его применить, тк по сути COMPILE_TIME_ASSERT - declaration. Всё-таки typeof рано или поздно появится в стандарте. Это лишь вопрос времени.
      Ответить

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