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

    +922.2

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    __declspec(noreturn) int FastAdd(const int a, const int b)
    {
      __asm mov eax, a;
      __asm mov ebx, b;
      __asm add eax, ebx;
    };

    Встречаеться множество подобных функций в одном С++ проекте, который в данный момент разгребаю. Хочеться что-нибудь сказать автору. Например: "на XYZ"?

    Запостил: Говногость, 08 Января 2010

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

    • Как обменять два целых числа за минимальное число операций на Паскале?
      asm
      mov ax, a
      mov bx, b
      mov a, bx
      mov b, ax
      end;
      Из памяти в память писать запрещено.
      4 команды. А обычный обмен или через ксор делает 6 операций.
      Ответить
      • К чему это? У нас сдесь не обмен, а простейшая операция и думаю, что компилятор это сделает лучше. Темболее, что сдесь ещё и вызов функции, что дополнительное падение производительности.
        Ответить
        • Ну вроде такие вещи автоматом инлайнятся. Просто оптимизация из той же серии.
          Ответить
          • Чем эта оптимизация отличаеться от (a+b) ? Какой код будет сгенерирован для этого выражения? Мне кажеться похожий, а то и быстрее. Вдруг какая-то переменная к этому времени будет храниться уже в регистре. К тому же с заинлайненой ассемблерной функцией компилятору будет тежелее оптимально распределять регистры.
            Ответить
          • Прикол в том, что компилятор может учитывать особенности конвейера процессора, так чтобы операция сложения вополнялась параллельно с предыдущими/последующими операциями, а такой всё отменяет
            Ответить
      • Что-за обмен ксором? Слышал про 1)обмен с вычитанием и сложением и 2)через дополнительную переменную или регистр.
        Ответить
        • void swap(int * a, int * b){
          /* в случае a == b (указывают на один int) функция не работает */
          assert(a != b);

          *a ^= *b;
          *b ^= *a;
          *a ^= *b;
          }
          Ответить
          • Ясно. Очень похоже на обмен с + и -.
            Ответить
          • А почему функция не работает для совпадающих адресов значений? Разве алгоритм нарушаеться и не работает? Вроде все также должно работать...
            Ответить
            • XOR самого себя даёт ноль, просто обнулишь переменную.
              Ответить
              • Тоесть если:
                a=5;
                b=5;
                То swap(a,b) приведёт к тому, что в a и b будут лежать нули?
                Уж лучше тогда + и - использовать, чем такой не безопасный обмен...
                Ответить
                • Сорри, ошибся. Работать будет, просто нет смысла возиться с одинаковыми переменными
                  Ответить
                  • Нет, если
                    i=5
                    j=5
                    то swap(a[i], a[j]) приведёт к двум нулям, даже если a[i] было вовсе не ноль.
                    Ответить
                    • Когда писал последний каммент, забыл, что там указатели, а не переменные))
                      Ответить
                • +и - для совпадающих адресов тоже даст 0
                  a = a + b; // a = a + a;
                  b = a - b; // a = a - a;
                  a = a - b; // a = a - a;
                  Ответить
          • Тогда есть более хороший вариант:
            void swap(int * a, int * b){
            /* в случае a == b (указывают на один int) функция работает */
            if(a == b)
            return;
            *a ^= *b;
            *b ^= *a;
            *a ^= *b;
            }
            Ответить
            • Ага... до поры до времени пока a не будет равно b
              Ответить
              • Ты протупил. Нечего страшного не будет, ибо есть:
                if(a == b)
                return;
                Ответить
      • mov ax, a
        xchg ax, b
        mov a, ax

        Ну, померялись, дальше что? :)
        Ответить
        • +1
          Ответить
        • xchg рекомендуют не использовать, так как это операция с 2 результатами... несколько mov могут выполниться параллельно, заняв разные конвееры, итого 3 такта против 2 у TarasB...
          размер кода не имеет значения еще со времен PPro...
          Ответить
    • Плюс, на сколько я знаю, эта радость не будет компилится некоторыми компиляторами (например, GCC), что порой очень плохо.
      Ответить
      • А почему? Вроде все по стандарту?
        Ответить
        • А на arm, mips, powerpc она тоже скомпилится, интересно?
          Ответить
          • Некоторые утверждают здесь среди комментов, что да, ибо at&t синтаксис - кросплатформенный.
            Ответить
        • В GCC спользуется другой формат ассемблерных вставок, там даже другой синтаксис ассемблера (например, вместо mov ebx, b; надо писать что-то типа "mov %0, %ebx" (операнды меняются местами))
          Ответить
          • А вроде как раз такое различается по __asm и asm, не? Помню, что в __asm надо писать aka MASM, а второй поддерживается остальными компиляторами, можэ в этом фишка?
            Ответить
          • O_o А зачем такой странный ассемблер в GCC? Неужели не могли сделать нормальный? Неужели это вообще правда... Даже не вериться... :(
            Ответить
            • Какой "такой"? Я про то и говорю, что по логике __asm -- это для MASM, а asm -- "нормальный". Но я не уверен.
              Ответить
            • Синтаксис at&t.
              Ответить
              • А в чем причины такого странного синтаксиса? Может я не знаю историю? Может есть ссылки, что-бы почитать, из-за чего так сложилось? Ну или хотя-бы в двух словах?
                Ответить
                • Там какие-то косяки с проприетарностью ассемблера от Intel были.
                  Ответить
                • at&t свой синтаксис придумали еще до того, как интел на свет появились. к тому же сделали его кросс-платформенным.
                  Ответить
                  • Почему это он кросплатформенный? И какие фишки позволяют ему таким быть?
                    Ответить
                  • http://ru.wikipedia.org/wiki/AT&T-синтаксис

                    Ничего в этом синтаксисе нет кросплатформенного.
                    Ответить
                    • Чего минусуете? Тогда объясните, почему он кросплатформенный?
                      Ответить
                  • Никогда не слышал о кросплатформенных ассемблерах. Разве что MSIL от Microsoft.
                    Ответить
                    • дадада MSIL - ассемблер и байт-код жабки с питоном тоже ассемблеры, угу, что уже весь моск проебал своим дотнетом?
                      Ответить
    • Почему сдесь используют __asm, а не asm{...}; ?
      Ответить
    • А просветите, че такое __declspec(noreturn)? Типа инлайн?
      Ответить
      • Типа можно в функциях не использовать return. Иначе будет warning. Значение возвращаеться через eax.
        Ответить
      • это значит что из этой функции нет выхода...
        подобным флагом обладает функция longjmp, exit, так как эти функции не возвращают управления... оптимизатор может выкинуть код идущий за этими функциями или кинуть варнинг...
        гость выше написал почему это используется здесь...
        Ответить
        • Ясно, спс)
          Ответить
        • Ээээ. Серьёзно? Не знал. Тогда выше написанный говнокод даже не будет работать. Ведь компилятор вообще выкинет дальше этих функций код. Жесть. Ну и говнокод...
          Ответить
          • Кстати ага.
            Ответить
          • не выкинет, а может выкинуть, я не знаю компиляторов которые выкинут, так как большинство не выкидывают даже код после ретурна считая что программист умнее и знает что делает... скорее всего появится варнинг о том что код после этой функции возможно не исполнится ни прикаких обстоятельствах...

            недавно у нас был проект с такими же заморочками, но там ребята еще и были в курсе про __fastcall...
            Ответить
            • Да. В том, проекте, откуда код. Там тоже много функций с __fastcall, а ещё c forceinline.
              Ответить
            • Тогда я до сих пор не догоняю, в чем смысл noreturn. Кроме варнинга, что еще будет?
              Ответить
              • Включенее оптимизации, неподходящей для данного случая, как я понимаю.
                Ответить
                • Я бы даже сказал: Устранение варнинга неподходящим неверным способом со слов pushkoff.
                  Ответить
              • вот вырезка из МСДН

                This __declspec attribute tells the compiler that a function does not return. As a consequence, the compiler knows that the code following a call to a __declspec(noreturn) function is unreachable.

                If the compiler finds a function with a control path that does not return a value, it generates a warning (C4715) or error message (C2202). If the control path cannot be reached due to a function that never returns, you can use __declspec(noreturn) to prevent this warning or error.
                Ответить
              • Для всяких хаков когда ты хочешь с какими-то целями сделать нестандартный выход из процедуры, или может вобще вместо выхода сделат jmp внутрь другой функции
                Ответить
        • Путаете noreturn и neverreturn (или как-то так). Т.е. в представленном говнокоде подавляется ворнинг "function should return value", а то, что вы описали (longjmp, exit) - это neverreturn
          Ответить
    • Где сдесь С++?
      Ответить
      • Кончился, зайди через недельку, может подвезут.
        Ответить
      • По-моему, тут можно спокойно соединять разделы с и с++ - их часто не различают.
        Ответить
        • По моему тут guest пишет это во все посты. Примерно раз в два дня. А вообще их не различают давно.
          Ответить
          • Какая-то школота на говнокоде завелась последнее время. Даже не смешно...
            Ответить
            • Сам-то че тогда стесняешься, взрослый умный гест?
              Ответить
              • Это я говорил не про тебя, но после последнего твоего вопроса - я в этом не уверен...
                Ответить
                • Мм. Да я не обижусь если и про меня. Я школота, и ты школота, смотря с кем сравнивать. Только вот не стОит про других так говорить, особенно если причина -- "не смешно".
                  Ответить
                  • Ну хоть понимаешь ошибку. Больше так не делай. :p
                    И если не знал, то guest - не зарегистрированный пользователь. Под ним может сидеть кто угодно. ;)
                    Ответить
                    • Веришь или нет -- довольно быстро догадался. Странно, что из фразы ты сделал такой вывод.
                      Ответить
                      • Почему странно?
                        Ответить
                        • Потому что я был бы дико, ну просто ДИКО туп, если бы думал что тут три человека сидят и один из них сам с собой спорит в 70% постов.
                          Ответить
                          • Кстати, ты дико туп, если думаешь, что только одного человека беспокоит, когда путают си и си++
                            Ответить
                          • Это не я написал! Гости начали, за других гостей отвечать. >_<

                            Сделайте же с этим что-нибудь... Неужели сложно запретить Анонирование Анонимусов?
                            Ответить
                            • А я не к guest обращался, а к guest. Пумпурум.
                              Ответить
                              • Ничего не понимаю...
                                Ответить
                                • Я про то, что гостей не различаю. По форме ответа не понятно ты это отвечал или нет, поэтому я отвечал ГОСТЮ. Абстрактному гостю.
                                  Ответить
          • Вообще, может действительно есть смысл объединить разделы?
            Ответить
            • Да вроде разные языки. Сейчас об этом только старожилы помнят и программисты встроенных систем (девайсов). Ну ещё программисты драйверов для старой дровяной модели.
              И ещё сам СтраусТруп говорит, что добиться полной совместимости С++ с Си не получилось. Можно встретить такие проги Си, что не скомпилятся С++ компилятором или скомпилятся не верно. Хотя сам такой пример привести врятли смогу.
              Ответить
              • Помоему в Си можно было обращаться к массивам как-то так: [3]a или 3[a] или ещё как-то. В С++ так точно нельзя. Другие примеры не вспомню.
                Ответить
                • Неправда, специально проверил:
                  class PRN{
                  public:
                  	PRN();
                  	int a[10];
                  	void fprint(void);
                  };
                  
                  PRN::PRN()
                  {
                  	a[0]=0;
                  	a[1]=1;
                  	a[2]=2;
                  	a[3]=3;
                  	a[4]=4;
                  	a[5]=5;
                  	a[6]=6;
                  	a[7]=7;
                  	a[8]=8;
                  	a[9]=9;
                  }
                  
                  void PRN::fprint(void){
                  	printf("%d,%d\n",this->a[0],3[a]);
                  }
                  
                  int _tmain(int argc, _TCHAR* argv[])
                  {
                  	int n=10;
                  	PRN tab;
                  	tab.fprint();
                  	scanf("\n%d",n);
                  	return 0;
                  }


                  Нормально компилируется и работает. P.S. на говнокоде не перевыкладывать писалось на коленке.
                  Ответить
                  • К чему это? Вроде здесь нет ни [3]a, ни 3[a] при обращении к массиву?
                    Ответить
                    • printf("%d,%d\n",this->a[0],3[a]);
                      Ответить
                      • Нифига себе... O_o
                        Ответить
                      • Может кто-нибудь объяснить, к какому элементу массива приведет это обращение 3[a] и вообще как это понимать? Как объяснить логически?
                        Ответить
                        • погугли, это уже давно боян
                          Ответить
                          • Объясни пожалуйста, если не сложно. Даже уже +1 появилась над фразой. Кто-то тоже не понимает. Скажи хотябы, какие слова загуглить?
                            Ответить
                            • "c++ массивы", "c++ обращение к элементам массива"
                              Ответить
                            • Смотри, повторяю фокус, но медленно, без дыма и зеркал:
                              char arr[] = "qwerty";
                              arr[2] == 'e';
                              //массив можно привести к указателю. С указателями можно складывать числа:
                              *(arr+2)=='e';
                              //от перемены мест слагаемых сумма не меняется
                              *(2+arr) == 'e';
                              //возвращаемся к старому синтаксису
                              a[arr] == 'e';
                              Ответить
                          • Ой. Случайно на -1 нажал. Второй раз счелкнуть не даёт. Хотел +1.
                            Теперь коммент +2 виртуально имеет.
                            Ответить
                        • переставь местами имя и цифру - поймёшь.
                          Ответить
              • в С99 можно сделать так

                void f( const int n )
                {
                int mas[n];
                .......
                }
                Ответить
              • Так, к слову... Я имел ввиду что здесь их не различают в основном. Я вот, тоже не отличу скорее всего)
                Ответить
            • Там где-то наверху можно предложения вносить. В "отзывы" вроде.
              Ответить
            • В Си есть возможность объявлять функции с возвращаемым значением - int поумолчанию (int не указываеться, но возвращаеться). В то время, как в С++ нет. Вот и ещё одна несовместимость. Определенно можно найти проги Си, не компилирующиеся в С++.
              Ответить
              • Эт как? В c++ нет возвращаемых значений? То есть int f() ничего не возвращает? Или про что?
                Ответить
                • В Си f() - возвращает int, а в С++ так нельзя.
                  Ответить
                  • В С++ можно только int f()
                    Ответить
                    • В чем разница-то? Что можно не писать int перед именем метода?
                      Ответить
                      • в си нет методов.
                        Ответить
                        • Может на вопрос ответишь, а не к словам цепляться будешь?
                          Ответить
                      • В Си перед именем функции в объявлении необязательно писать int. Он подставиться сам. В С++ он сам не подставляеться...
                        Ответить
                        • Понял, спс.
                          Ответить
                        • Если копнуть чуть глубже, то в C допускается вызывать функции без объявления, компилятор сам должен сгенерировать его по фактическим параметрам
                          Ответить
    • Ув. тов. Говногость. Слова Встречаеться, кажеться, отличаеться - пишутся без мягкого знака. А тежелее - с буквой Я. Эт так, к слову... А то как говнокод обсирать, так мы тут умные.
      Ответить
      • Ув. Тов. Grammar Nazzi.
        Проверьте, пожалуйста, правильность написания моих постов.
        С Уважением
        Антон, 25 лет
        Ответить
      • А ты и тут ошибся. Мягкий знак пишется в неопределенной форме, и только. Что делать? - Отличаться. Что делает - Отличается.
        Так что сам не умничай.
        Ответить
        • Даже специальный сайт есть tsya.ru
          Ответить
      • Ты или смирись, что в интернетах так, либо иди с посохом по всем форумам.
        Ответить
        • В интернетах так, ибо 95% этих ваших интернетов - школота безграмотная. Что теперь, равняться на говно? Увольте меня!
          А безграмотность лично меня бесит сильнее, чем любой говнокод.
          Простите, не удержался
          Ответить
      • Щитаю шо нужна песать правельно.
        Ответить
        • С большой буквы и точкой на конце. Низачёт.
          Ответить
          • точна блин
            низащот
            будим испровлаца
            Ответить
    • однако...
      я так понимаю, что этот сумматор просто используется для каких-то стандартных алгоритмов... std::for_each или что-либо в этом же духе
      экономилось время программиста...
      при чём тут говнокод?
      Ответить
      • Зачем тогда он суммирует встроенные типы? Ладно б какие-то структуры, но с этим и компиллятор справится.
        Ответить
      • А почему тогда на ассемблере написали? Помоему в такой высокоуровневой вещи, как for_each нет места такому низкоуровнему %$#.
        Ответить
        • Сложно представить, какие у людей бывают представления о "место-не место"..
          Ответить
          • Место-то есть и какое-нибудь sse туда можно было бы засунуть (если бы с флоатами работали). Но тут кто-то просто выпендривался. Наверно, недавно ассемблер выучил.
            Ответить
            • +1
              Ответить
            • sse ускоряет операции только для множества параллельных операций. В for_each они идут последовательно. Для каждого элемента по отдельности. Так, что неподойдёт это для sse даже с флоатами. for_each не более одного элемента за раз выдает.
              Ответить
    • Ёёёёё.... Уже 110 комментов? Что-то я на говнокоде такого даже и не припомню...
      Ответить
    • Где здесь С++?
      В раздел ассемблера это унылое не смешное говно. Ему место там.
      Ответить
      • А тут смешно не должно быть. Тут какашке на сайте, оне не смешные. Сходи лучше на govnopetrosyangovnistoesmeshnoegovno.nax .
        Ответить
        • Скоро появится домен nax специально для редиректа.
          Ответить
        • Разве не главный девиз:
          Код, на который без улыбки не взглянешь?
          Нет тут такого. Не смешно. Плакать хочеться.
          Ответить
          • Радуйся, что это не твой код. Смейся и пляши.
            Ответить
          • Главный девиз "нельзя назвать нормальным". Хочешь посмеяться -- читай новости. А тут лучше смотри, как писать не нужно. А посмеяться -- вопрос десятый.
            Ответить

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