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

    +5

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    #include <stdio.h>
    #define UPP 300
    float conversion(float fahr);
    
    main(){
    	float far;
    	int a;
    	a = UPP;
    	for(far = 0; far <= a; ++++++++++++++++++++++++++++++++++++++++far)
    		printf("%.f\t%.1f\n", far, conversion(far));
    }
    
    float conversion(float cels){
    	float c;
    	c = ((5*(cels-32))/(9));
    	return c;
    }

    how do I make it 20 by 20 in a shorter way, without having to put 20 times "++" please

    https://www.reddit.com/r/C_Programming/comments/ff5zph/how_do_i_make_it_20_by_20_in_a_shorter_w ay/

    Запостил: eukaryote, 08 Марта 2020

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

    • Where is C++, eukaryote?!
      Ответить
      • Behind the cheek, check it out.
        Ответить
      • А разве C, C++ и C# — не одно и то же?
        Тут проблема в том, что он пытался писать на «C», но компилировал «Dev-C++». В итоге получилось говно, которое могут сожрать только кресты. Поэтому «C++».
        Ответить
        • Действительно, «C++» здесь в той строчке, где больше всего плюсов. Поэтому язык так и назвали.

          Сишка не может проглотить ++++++++++++++++++++++++++++++++++++++++ far:
          error: lvalue required as increment operand
          Ответить
          • Более того, такую волшебную конструкцию не позволяют себе ни «Java», ни «C#», ни даже «JavaScript».
            Именно поэтому я за.
            Ответить
            • Даже «PHP» не позволяет: не пишет ничего про lvalue и rvalue, просто сообщает, что не может распарсить, даже скобочки не спасают ситуацию.
              Ответить
        • Перевёл на «Си»:
          float* pp(float* x) {
              ++*x;
              return x;
          }
          
          ...
          
          for(far = 0; far <= a; pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(pp(&far)))))))))))))))))))))
          
          ...


          https://ideone.com/1KMvNh

          К сожалению, ничего изящнее в рамках чистой сишки придумать не могу.
          Ответить
          • >К сожалению, ничего изящнее в рамках чистой сишки придумать не могу.
            Попробуй #define.
            Взрослые говорят что он вреден, но это ложь.
            Ты сможешь отказаться #define в любой момент.
            #define делает жизнь интереснее и ярче.
            Если использовать препроцессор редко, то зависимость не возникает.
            Ответить
      • how can you write ++++++++++ in plain old c? don't u need an overload?
        Ответить
        • а не, тут не вэтом же фишка

          в с# можно перегрузить плюсплюс, но он вернет не lvalue, и у него уже нельзя вызвать ++
          Ответить
    • переменную под константный макрос он выделяет, ты посмотри на него
      Ответить
      • Какой анскилл )))
        Ответить
      • Починил.
        #include <stdio.h>
        #define UPP 300
        
        template<int n>
        void plusplus(float& x) {
            plusplus<n-1>(++x);
        }
        
        template<>
        void plusplus<0>(float& x) {
        }
        
        
        
        float conversion(float fahr);
        
        main(){
        	float far;
        	for(far = 0; far <= UPP; plusplus<20>(far))
        		printf("%.f\t%.1f\n", far, conversion(far));
        }
        
        float conversion(float cels){
        	float c;
        	c = ((5*(cels-32))/(9));
        	return c;
        }


        https://ideone.com/IKPf7X
        Ответить
    • Кстати, есть ли в сишке типы данных, для которых инкремент определён, а арифметические операции — нет?

      В «Паскале» есть отдельный символьный тип данных, там можно написать Inc(bukva); или bukva = Succ(bukva); а вот bukva := bukva + 1; написать нельзя.

      В «C++» можно создать класс с перегрузкой операторов, у которого перегрузить операторы ++ и --, а про арифметические операторы «забыть».

      А вот в сишке что-то подобное бывает?
      Ответить
      • По Стандарту,
        The value of the operand of the prefix++ operator is incremented.
        The result is the new value of the operand after incrementation.
        The expression ++E is equivalent to (E+=1).

        § 6.5.3.1/2 (N2346)
        Так что нет, не бывает.
        Ответить
        • А теперь приведём реальный пример в крестах:
          class Petuh
          {
          private:
              int value;
          public:
              Petuh(int i): value(i) {}
              friend const Petuh& operator++(Petuh& i) {++i.value; return i;}
              operator int() {return value;}
          };
          
          int main() {
            Petuh x{42};
            ++x;  // всё отлично, есть перегрузка
            x = x + 1; // скомпилируется, потому что мы определили каст в инт:
                            // x.operator=(Petuh(static_cast<int>(x.operator int()) + 1));
                            // будет переголова: создание нового петуха
            x += 1; // не скомпилируется, потому что += мы не перегрузили
          }
          Ответить
          • Ага.
            Кстати, в крестах есть https://en.cppreference.com/w/cpp/types/byte, для которого определены только битовые операции.
            Ответить
            • Мне не понравилось, как в моём примере компилируется x = x + 1;

              Компилятор сам догадывается вызвать у x оператор int(), хотя я его об этом не просил. В более реальных примерах это может привести к непредсказуемой питушне.

              Вероятно, именно поэтому у std::byte не стали перегружать операторы каста, а просто сделали метод to_integer.
              Ответить
              • Добавил «explicit», проверь:
                class Petuh
                {
                private:
                    int value;
                public:
                    Petuh(int i): value(i) {}
                    friend const Petuh& operator++(Petuh& i) {++i.value; return i;}
                    explicit operator int() {return value;}
                };
                
                int main() {
                  Petuh x{42};
                  ++x;  // всё отлично, есть перегрузка
                  x = x + 1; // no match for operator+
                }
                Ответить
                • Спасибо. Интересная директива.

                  https://en.cppreference.com/w/cpp/language/explicit
                  Ответить
            • byte is like char and unsigned char, but unlike those types, it is not a character type and is not an arithmetic type

              Самурай без меча подобен самураю с мечом, но только без меча.

              Зачем? Зачем?
              Чтобы повысить семантичность? Теперь у нас есть char, int8_t и byte?
              Ответить
              • Косплей.

                В языке Ада строгая типизация, предикаты, контракты. В нём нельзя просто так скопировать символ в число. Нужно указать, что именно ты хочешь получить.

                Крестостандартизаторы захотели сделать что-то, как у взрослых дяденек, не переделывая сам язык. Для этого они наговнокодили класс из соломы и банановых листьев с нужными перегрузками и с директивой explicit.
                Ответить
                • byte - это вообще enum, емнип.
                  Ответить
                  • Проверил. Это enum class. Так называемое «scoped enumeration». Обычные enum'ы, как в сишке, называются «unscoped enumerations».

                    There are no implicit conversions from the values of a scoped enumerator to integral types, although static_cast may be used to obtain the numeric value of the enumerator.

                    То есть в кресты начинают потихоньку добавлять строгость и явность, которые в «Паскале» были изначально.

                    enum class вроде добавили только в C++11, раньше его не было?
                    Ответить
                    • > строгость и явность, которые в «Паскале» были изначально.

                      Питушня там, а не «строгость и явность».
                      В кресты завозят не настолько сырые концепты.
                      Ответить
              • Ты ещё забываешь о том, что char может вести себя (иметь в качестве underlying type) как unsigned char или signed char, но при этом char — это не unsigned char и не signed char, это отдельный тип. А вот int и остальные — это, ЕМНИП, в точности signed int. Теперь ещё в эту клоаку добавили и std::byte.
                Ответить
                • Точно, в этом году обсуждали:
                  https://govnokod.ru/26318#comment519640
                  https://govnokod.ru/26389#comment523404
                  Ответить
          • > реальный пример в крестах
            Это питушня. Там можно сломать математику и писать в константную питушню. Написать любой питухкод.

            Реальный пример - std::list<pituz>::iterator.
            Ответить
      • Смотря какие арифметические операции. Указатели нельзя умножать и делить, брать остаток от деления - а прибавлять и вычитать можно только с определенными ограничениями

        https://overiq.com/c-programming-101/pointer-arithmetic-in-c/
        The only valid arithmetic operations applicable on pointers are:

        1) Addition of integer to a pointer
        2) Subtraction of integer to a pointer
        3) Subtracting two pointers of the same type

        При этом ++ -- вполне работает
        Ответить
        • Поскольку к указателям можно прибавлять целое, то для указателей возможны такие операции:
          1. ++p, --p
          2. p = p + 1, p = p - 1
          3. p += 1, p -= 1
          Более того, они эквивалентны.

          Тут всё хорошо.

          Значит, примера, когда в сишке нужно применять именно ++p, потому что другие операции отсутствуют или неэквивалентны, нет?
          Ответить
        • Там еще, емнип, нельзя выходить за пределы выделенной памяти больше, чем на 1 объект (причем последний даже нельзя разыменовать)

          Сишка ваш сложный
          Ответить
          • Интересно, под какую питушню это заточено? Тот факт, что кусок можно выделить на краю и переполнить указатель, можно проверить через сравнение с краями домена указателей или какой-нибудь сайзмакс вставить, на который нельзя отдаляться от начала блока. Но такое... Зачем? Зачем?
            Ответить
            • может быть иногда полезно написать цикл с постусловием. В конце цикла указатель будет равен sizeof(petuh) +1, его проверят, поймут, что он больше размера, и выйдут из цикла. Это лучше, чем заводить под это отдельную инту. Но можно конечно очень легко объебаться, разыменовать его, и поймат убэ
              Ответить
            • Не знаю насчёт сишки, но в крестах это обеспечивает классическую идиому итерирования:
              for (auto it = container.begin(); it != container.end(); ++it) { ... }


              В принципе, container.end() может быть чем угодно, главное, чтобы инкремент итератора, указывающего на последний элемент, возвращал этот самый container.end().
              На практике же для какого-нибудь std::vector итератор — это просто (обёрнутый) указатель на соответствующий элемент во внутреннем массиве. В результате vec.end() — это указатель на элемент, следующий за последним (т.е. «arr + arr_size»).
              Такой подход позволяет делать итераторы и их инкременты максимально быстрыми.
              Ответить
              • Вероятно, я написал неправильно сформированную питушню, а меня поняли не как скриптушка, который из любого рукава достаёт undefined, а как крестушка, который хочет на такие случаи std::vector::at и строгость.

                Мне понятно, почему плохие указатели не нужно разыменовывать, но вот абсолютно неясно, чем может насолить хранение плохого указателя. Под какой платформой начинается питушня, если кто-то сохранил указатель не туда, вычисление которого не вызвало переполнение и влезло в максимум для size_t, что это включили в стандарт?

                P.S. Ну я вообще ещё не сильно понимаю, почему ещё диапазон size_t ограничен чем-то, кроме размеров size_t, и это ограничение не связано с конкретным типом (если бы у меня были питухи по 1 инту и по 100000 интов, я бы не удивился, если std::array<int, 1>::size_max был бы больше std::array<int, 100000>::size_max, и это бы вызывало компиляцию в более короткий size_t для второго случая), а стоит для всего языка.
                Ответить
                • Насколько я помню (Стандарт не смотрел, но если что — могу упороться), хранение «плохого указателя» не «запрещено», а является UB. Соответственно, скорее всего, Комитету просто было лень описывать все возможные поведения указателей (сишка проектировалась в том числе под платформы, на которых укококозатель — это более сложная сущность, чем просто число, а, например, пара смещение+сегмент).
                  Видимо, дальше они решили, что хранить покоцанные указатели никому нинужно, а раз нинужно — значит, можно просто забить хуй и не определять поведение этого говна.

                  Вообще, у меня складывается впечатление, что когда Комитету лень что-то делать — он это что-то объявляет UB и течёт.

                  Да, а что не так с size_t?
                  По Стандарту,
                  The type size_t is an implementation-defined unsigned integer type that is large enough
                  to contain the size in bytes of any object.

                  § 17.2.4/3 (N4842)
                  То есть каких-то исхуйственных ограничений не ставится, это просто беззначный инт, в который влезет размер самого большого объекта, который на целевой машине можно в теории создать.
                  Ответить
                  • > укококозатель — это более сложная сущность, чем просто число, а, например, пара смещение+сегмент
                    О, вот тогда мотив ясен, спасибо!

                    > Да, а что не так с size_t?
                    Мне казалось, что в мире C/C++
                    UINT_MAX == pow(2, sizeof(int) * CHAR_BIT)) - 1,
                    а
                    SIZE_MAX < pow(2, sizeof(size_t) * CHAR_BIT)) - 1,
                    и потому size_t выделяется на фоне остальных чисел, все биты которой забивают полезной информацией. Хотя, я мог спутать это с ptrdiff_t или ещё какой питушнёй.
                    Ответить
                    • Поискал. В крестостандарте SIZE_MAX вообще нет (какой анскилл), поэтому полез в сишный. Там SIZE_MAX должен быть не меньше 65535, а SIZE_WIDTH — не меньше 16 (в крестах size_t тоже должен быть не меньше 16 бит шириной, но там это явно указано, а не через константу). При этом пишется, что «The following object-like macros [gost: включая SIZE_MAX] specify the minimum and maximum limits of integer types corresponding to types defined in other standard headers» (§ 7.20.3/2, N2346).
                      Ко-ко-кокая-то залупа там с «rsize_t»:
                      [...]Functions that have parameters of type rsize_t consider
                      it a runtime-constraint violation if the values of those parameters
                      are greater than RSIZE_MAX.

                      § K.3.5/2 (N2346)
                      For those reasons, it is sometimes beneficial to restrict the range of object sizes to detect programming
                      errors. For implementations targeting machines with large address spaces, it is recommended that
                      RSIZE_MAX be defined as the smaller of the size of the largest object supported or (SIZE_MAX >> 1),
                      even if this limit is smaller than the size of some legitimate, but very large, objects. Implementations
                      targeting machines with small address spaces may wish to define RSIZE_MAX as SIZE_MAX, which
                      means that there is no object size that is considered a runtime-constraint violation.

                      § K.3.5/4 (N2346)
                      Ответить
                • Емнип, за хранение кривого указателя стандарт тебя не осудит. А вот за операцию, в результате которой ты его получил - вполне. Это как с операциями, которые приводят к переполнению инта.
                  Ответить
            • >Интересно, под какую питушню это заточено? Тот факт, что кусок можно выделить на краю и переполнить указатель

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

            А ещё нельзя кастовать указатели на функции в обычные и наоборот - к примеру, на ARM'е указатель на функцию может быть нечётным (+1 от настоящего адреса).
            Ответить
            • Там еще и память надо всегда выравнивать емнип
              А x86 позволяет и невыровненную, просто томрозит. Ассемблер x86 для скриптушков-неосиляторов, чо уш
              Ответить
              • Там забавный эффект на некоторых есть, когда при доступе к кривому адресу он выравнивается, а значение *прокручивается*. Т.е. допустим по адресу 0x1000 ты видишь 01 02 03 04, а по адресу 0x1001 - 02 03 04 01.
                Ответить
                • наверняка же есть цари, которые на это завязались (как на 20й бит у первых x86)?
                  Ответить
                  • Ну на такое грех не завязаться, можно же целую инструкцию сэкономить.
                    Ответить
              • >А x86 позволяет и невыровненную, просто томрозит.

                Кстати в последних итерациях штеуда и фьв unaligned access тормозит уже гораздо меньше.
                Ответить
            • А может быть так, что указатели вообще указывают на разные пространства, и кастовать их физически нельзя?

              Например, у меня сегментная модель, и там есть сегмент кода, и сегмент данных, и они разново размера?

              То-есть при всем желании это корректно не сделать
              Ответить
            • > А ещё нельзя кастовать указатели на функции в обычные и наоборот

              В стандарте POSIX на это забили хуй
              https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html

              > Note that conversion from a void * pointer to a function pointer as in:
              fptr = (int (*)(int))dlsym(handle, "my_function");

              > is not defined by the ISO C standard. This standard requires this conversion to work correctly on conforming implementations.

              Поэтому я за POSIX
              Ответить
              • То-есть на гарвардскую архитектуру уникса не портировать? Ясно-понятно
                Ответить
                • Ну да, а как там делать dlopen?
                  Ответить
                  • Можно намутить особую говноархитектуру, где будет особая инструкция, которой можно из обычной оперативной памяти копировать байтики в особую исполняемую оперативную память, и наоборот. И чтоб указатели на исполняемую память и обычную оперативу могли быть даже разного размера
                    Ответить
                    • Ну гарвардскую архитектуру обычно не от хорошей жизни юзают... Поэтому этой инструкции придётся флешку прошивать.
                      Ответить
                      • > Поэтому этой инструкции придётся флешку прошивать.

                        Именно так и есть в 8-битных AVR
                        Ответить
                        • А на stm'ках можно просто снять блокировку с флешки, форматнуть регион и писать в нужные адреса без всяких там инструкций. Именно поэтому я за арм.
                          Ответить
                    • да-да, причем чтобы это можно было делать только при наличии спец флажка, тогда обычное приложение этого делать не сможет, и будет супербезопасно

                      как W^R
                      Ответить
                      • >как W^R
                        Вот только хотел написать.

                        Имелось ввиду W^X, да?
                        Ответить
                        • конечно:)

                          Вопрос для хакеров: как они реализовали W^X на 32х битах?
                          Ответить
                          • >W^X на 32х битах
                            i386 CS, DS

                            С пентиумов адресация стала 36-разрядная.
                            По-народному называется PAE.
                            Ответить
                            • так а на уровне страниц же не было защиты, а в CS можно де было писать

                              >36
                              Это при PAE
                              Ответить
                    • > особую говноархитектуру, где будет особая инструкция, которой можно из обычной оперативной памяти копировать байтики в особую исполняемую оперативную память, и наоборот.

                      В x86-64 намутили ещё в 2005.

                      >из обычной оперативной памяти копировать байтики в особую исполняемую оперативную память

                      Запахло DEP и NX bit.
                      Ответить
                  • спец опкод сделать для копирования
                    Ответить
                    • Да есть на атмеловских чипах. Можно и читать флешку и шить. И флажок есть, как ты описал. Только там разделения привилегий нету, поэтому просто защита от дурака и убежавшего кода.
                      Ответить
              • Кстати, а для thumb функции на ARM'е оно вернёт указатель с thumb битом (нечётный)?

                З.Ы. Вечером проверю.
                Ответить
            • На ARM два младших бита указателя на код используются для выбора набора инструкций («Thumb» и типа того). Настоящий адрес всегда кратен четырём. Верно или я что-то путаю?
              Ответить
              • На тхумбе вроде двум? Не помню.
                Ответить
                • Действительно. Его же придумали, чтобы экономить байтики, когда навороченные инструкции не нужны.
                  Ответить
                  • Всё что угодно экономит байтики, по сравнению с штед
                    Ответить
                    • Именно поэтому я за «Штеуд».
                      Ответить
                      • Штеуд это такой пхп в мире цпу
                        Ответить
                        • А Царь говорит, что «Штеуд» — единственный вменяемый процессор, а «gcc -O2» — единственная вменяемая команда для конпеляции.
                          Ответить
                  • А потом добавили туда навороченые составные инструкции...
                    Ответить
        • >Указатели нельзя умножать и делить, брать остаток от деления - а прибавлять и вычитать можно только с определенными ограничениями

          Гру́ппа в математике — множество, на котором определена ассоциативная бинарная операция, причём для этой операции имеется нейтральный элемент (аналог единицы для умножения), и каждый элемент множества имеет обратный.

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

            Это скорее как точки на отрезке - я могу измерить расстояние между ними, могу прибавить или отнять от их координат число и получить новую точку, но сами точки я складывать не могу.

            Т.е. это метрическое пространство, а не группа.
            Ответить
      • А, ну и еще для флоатов и даблов не работает взятие остатка от деления «%»
        Ответить
        • >ну и еще для флоатов и даблов не работает взятие остатка от деления «%»

          Но зачем-то в стандарт приделана функция fmod.
          Ответить
    • >float far;
      > for(far = 0; far <= a; ++++++++++++++++++++++++++++++++++++++++ far)

      Все обсуждали обилие плюсов.
      Но никого, как я понимаю, не смутил цикл по плавающим питухам.
      Ответить
      • в джаваскрипте можно
        > let a = 1.1;
        undefined
        > a++;
        1.1
        > a++;
        2.1
        > a++;
        3.1
        >
        Ответить
        • Багры плав. питухов здесь разбирались уже 100500 раз.
          Ответить

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