1. C++ / Говнокод #12078

    +22

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    int AzFl_PSD_Image::ReadIntFromPsdFile(const unsigned char *offset)
    {
    	char i[4];
    	i[0] = offset[3];
    	i[1] = offset[2];
    	i[2] = offset[1];
    	i[3] = offset[0];
    	int *r = (int*)i;
    	return r[0];
    }

    Невиноватый я что програмисты из адоба биты задом на перед в файл пишут :`(

    Запостил: Psionic, 08 Ноября 2012

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

    • Ну, говорят, формат PSD это та еще хрень... и дело не в BigEndian.
      Но тут, конечно, зависимость от порядка байт платформы вводится зря. И длина, возможно, не проверяется (а что если файл обрезан, и offset[3] уже за концом?).
      Ответить
      • Как это обрезан, это метод для париснга псд заголовка, если файл кончется на заголовке - это битый файл.
        Ответить
        • Битый файл это повод выдать сообщение "Файл битый", а не упасть к чертовой бабушке.
          Ответить
        • зачем парсить двоичный файл?
          Ответить
    • Но это совсем не повод делать говнокасты:
      // Big-endian
      return offset[0] << 24 | offset[1] << 16 | offset[2] << 8 | offset[3];
      // Little-endian
      return offset[3] << 24 | offset[2] << 16 | offset[1] << 8 | offset[0];

      Этот код работает всегда и везде (лишь бы инт был 32 бита). А ваш костыль на Big-endian платформе заломается.
      Ответить
    • man ntohl?
      Ответить
    • я бы просто вызвал POSIX htonl/ntohl, а то вдруг psd файл придется открыть на big-endian платформе
      пусть платформа сама перевернет, если ей этого надобно
      Ответить
      • А еще на SPARC64 64битные инты. Поэтому этот код прочитает мусор из стека в половину этого инта.
        Ответить
        • код из ОП? да
          Ответить
          • Конечно, а если он напишет return ntohl(*(int*)offset), то оно, при неудачном стечении обстоятельств упадет с Alignment Fault на АРМах, которые привередливы к выравниванию...

            А еще, к примеру, на восмибитных AVR инт занимает 16 бит. Поэтому там ничего не влезет, и автору следовало юзать uint32_t или его аналоги.

            Я уж не говорю о процессорах, на которых байт состоит не из 8 бит...
            Ответить
            • Вам, как лучшему покупателю, байты по 9 бит!
              Ответить
              • И не устаревшие двоичные процессоры, а современные троичные! Malbolge
                Ответить
      • Пусть платформа сама перевернётся, если ей надо.
        Ответить
    • показать все, что скрытоЯ уже нагуглил - да черт возьми некоторые (как я понял не из х86 семейства компьютеры) хранят разряды "задом на перед", Big-endian/Little-endian. Вопрос: я просто не знал - но адоб зачем это делает.
      Ответить
      • да почему задом наперед то?
        это x86 их задом наперед хранит
        в big-endiane они как раз по-человечески распогалаются
        0x12345678 хранятся как 12 34 56 78, а на маленьком ендейце будет 78 56 34 12
        Ответить
      • > но адоб зачем это делает
        Да многие так делают. В Qt сериализация в QDataStream по дефолту настроена на Big endian, в ява машинах .class файлы тоже, даже порты в низкоуровневых структурах для работы с сокетами записываются "задом наперед"...
        Ответить
        • А я думал, что прогеры на С++ низкоуровневый код умеют писать.
          Ответить
          • Вы хотите сказать, что я не умею писать низкоуровневый код? ;)
            Ответить
            • Да ;)

              Несмотря на то, что я не видел плохого кода в Вашем исполнении.
              Ответить
              • > Несмотря на то, что я не видел плохого кода в Вашем исполнении.
                Так узри же сейчас!

                http://govnokod.ru/11576
                http://govnokod.ru/11575
                http://govnokod.ru/11528
                http://govnokod.ru/10058
                http://govnokod.ru/10011
                Ответить
              • низкоуровневый - это кроссплатформенный портабельный ассемблер bswap?
                я если чо могу и fpga наваять, который тупо правильно заведенными линиями сразу перевернет - это достаточно низкоуровнево? мне не сложно, зря этому учили чтоли
                Ответить
                • А я вот не умею в FPGA, и из железячного умею паять и писать только под восьмибитки AVR, да и то это скорее хобби, чем работа. Ну и по работе еще приходилось сталкиваться с терминалом на ARM'е, но там самый обычный busybox и gcc...

                  P.S. Посоветуете кстати чего-нибудь из серии FPGA для нубов?
                  Ответить
                  • зачем? это бесполезные знания, если их не применять
                    да и не востребованные
                    еще спасибо институту, что в наше время уже проектировались, отлаживались в нормальной среде (xilinx), на выходе получая результат в fpga, а не собирали курсовики на стендах проводочками, как за несколько лет до нас
                    Ответить
                    • > зачем? это бесполезные знания, если их не применять
                      Ну так то да, придумать чего-то оригинальное с FPGA не могу. Все что приходило в голову уже кем-то сделано ;) Так что вы правы, забью я на это дело.
                      Ответить
                      • о fpga могут вспомнить, когда софтверно уже выходит слишком медленно, а бюджеты позволяют
                        какой-нибудь железячный шифратор-дешифратор
                        или биржевые спекулянты ради выигранной 1мс готовы тратить миллионы

                        а все остальное бытовое - ну какие сейчас еще кому нужны платы расширения
                        Ответить
          • Не всё то прогер что пишет на плюсах
            Ответить
          • Низкоуровневый код для каждой платформы свой, поднаготную каждой знать трудновато.
            Ответить
            • BE и LE - означают одно и тоже на всех платформах.
              Ответить
            • Поэтому нужно знать несколько простых правил, и всегда соблюдать их, тогда задумываться об особенностях платформы придется только в действительно сложных случаях:

              1) Размеры типов не фиксированы. В стандарте написано только то, что sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long), ну и то что sizeof(char) всегда 1 байт.

              2) Для хранения размеров всяких структур, лежащих в памяти следует применять size_t, а не unsigned, а если нужно считать разницу между указателями следует применить ptrdiff_t, а не int.

              3) Если нужен именно тип фиксированной длины - воспользуйтесь int8_t, int16_t и им подобными. В визуалке вроде бы их нет (ведь настоящим посонам С99 не нужен), поэтому как поступить в ней, мы спросим у @defecate++.

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

              5) На некоторых платформах есть проблемы с доступом к невыровненным данным. Начиная от снижения скорости, и заканчивая крашем с Alignment Fault. Поэтому не стоит бездумно юзать pragma pack и кастовать указатели из char* во что попало.

              Вроде бы всё...
              Ответить
              • 1. Самое смешное следствие этого пункта - по стандарту в таком нет ничего плохого:

                sizeof(char) = sizeof(short) = sizeof(int) = sizeof(long) = sizeof(long long) = 1

                4. Тут вообще нужно раскрыть тему undefined behavior.
                Ответить
                • Ну 4 это ЕМНИП не undefined behavior а implementation defined.

                  А вообще да. Правило 0.

                  0) Никогда без весомых причин (а у вас их нет) не используйте undefined behavior. Implementation defined использовать можно, но только если нет возможности написать по-другому.
                  Ответить
                • 1. неправда
                  фактический размер на платформе не имеет права не соответствовать (быть более урезанным) *_MIN, *_MAX, объявленных в стандарте
                  исходя из них, у short и int - минимум 16 бит длина
                  у long - минимум 32 бита
                  у long long - 64

                  3. есть boost/cstdint.hpp, который либо сам объявит нужные типы, либо возьмет из внезапно имеющегося стандартного аналога от компилятора
                  Ответить
                  • > у short и int - минимум 16 бит длина
                    > у long - минимум 32 бита
                    > у long long - 64
                    Хм. А вот это я как-то пропустил. Сорри за дезинформацию.

                    > есть boost/cstdint.hpp, который либо сам объявит нужные типы
                    Ок, спасибо.

                    P.S. Капча 9999.
                    Ответить
                    • почему дезинформацию
                      не вижу противоречия

                      можно вообразить платформу, где char, short и int будут занимать по 8 байт (64 бита)
                      и таким образом будет, например sizeof(char) = sizeof(short) = sizeof(int) = sizeof(long) = 1

                      так что скорее моя вина, "неправда" относилось к домысленному = 8 бит :)
                      Ответить
              • > sizeof(char) всегда 1 байт
                Тут, конечно, опечаточка: sizeof(char) == 1 by definition in C++, а сколько там байт - зависит от платформы
                Ответить
                • А там кстати вроде бы написано, что размер чара равен размеру байта, а вот сколько бит в байте - разработчик платформы его знает.
                  Ответить
                  • там - где?
                    в с++ ровно так, как сказал Роман
                    в с на sizeof(char) - как и на другие типы - таких ограничений, как в с++, не накладывается
                    Ответить
                • Вот так написано в C89:

                  6.5.3.4 The sizeof operator
                  2. The sizeof operator yields the size (in bytes) of its operand
                  3.When applied to an operand that has type char, unsigned char, or signed char, (or a qualified version thereof) the result is 1.

                  Так что char это 1 байт.
                  Ответить
                  • подтверждаю
                    в с++ при этом так же
                    единственный вариант - варьировать количество бит в байте
                    которых должно быть не менее 8 в связи с наложенными лимитами

                    в с++ раскрывается еще понятие байта в 1.7
                    Ответить
                    • bit - unit of data storage in the execution environment large enough to hold an object that may have one of two values.

                      Т.е. троичные машины вполне стандартны ;)

                      P.S. To hold an object. А кто-то еще говорит, что С это не объектно-ориентированный язык.
                      Ответить
                  • это не char 1 байт, а 1 байт = char (в понимании С). Иначе как получается возможность, что sizeof (char) = 32 bits = 4 physical bytes? Так что не все байты одинаково байтовы =)
                    Ответить
                    • > 4 physical bytes
                      Это другие байты, и в стандарте си они не рассматриваются. Поэтому противоречий тут нет.
                      Ответить
              • 1. Уже неточно. Прошу уточнить интерпретацию что такое "1 байт".
                Ответить
                • Почитайте уже стандарт, а?
                  byte

                  addressable unit of data storage large enough to hold any member of the basic character set of the execution environment

                  NOTE 1
                  It is possible to express the address of each individual byte of an object uniquely.

                  NOTE 2
                  A byte is composed of a contiguous sequence of bits, the number of which is implementation-defined. The least significant bit is called the low-order bit; the most significant bit is called the high-order
                  bit.
                  Ответить
                  • Удивительно, но там это действительно есть :-)
                    Ответить
        • Java <=> Ява
          Jazz <=> Язь
          Ответить
      • > но адоб зачем это делает
        Затем, что исторически он писался под 32 разрядный моторольный процессор 86000 (Мак), в котором порядок байтов обратный интеловскому
        Ответить
    • - Давай-ка задом, мила, - я шлёпнул Елену по ляжке, и она неловко перевернулась, встала на колени, высоко подняла зад.
      Ответить

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