На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> В буфере появляется лишний символ
    Здравствуйте!
    В программе перевода в двоичное число использую 2 функции:
    ExpandedWrap disabled
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
       
      template <class T> void TypeToBin(T source, char* buffer, int size)
      {
        buffer += size - 1;
        for (int i = size - 1; i >= 0; i--)
        {
          *buffer-- = (source & 1) + '0'; // '0' - 48 '1' - 49  printf("%p\n", buffer);
          source >>= 1;
        }
      }
       
      template <class T> char* TypeToBin2(T source)
      {
        int const size = 8 * sizeof(T);
        char *p = (char*) malloc(size + 1);
        p[size] = '\0';
        p += size - 1;
        for (int i = size - 1; i >= 0; i--)
        {
          *p-- = (source & 1) + '0'; // '0' - 48 '1' - 49  printf("%p\n", buffer);
          source >>= 1;
        }
        return p;
      }
       
      int main()
      {
        char a = 'a';
        //int a = 1;
        int const size = 8 * sizeof(a);
        char buffer[size + 1];
        buffer[size] = '\0';
        TypeToBin(a, buffer, size);
        printf("a = %s  strlen = %d\n", buffer, (int) strlen(buffer));
        printf("a = %s\n", TypeToBin2(a));
        printf("\n");
        system("pause");
        return EXIT_SUCCESS;
      }
    Первая функция TypeToBin выводит строку "a = 01100001 strlen = 8", а у второй функции TypeToBin2 вывод a = ¤01100001 содержит в начале какой-то символ. Подскажите, пожалуйста, какую ошибку я допустил в этой функции. Проект прикрепил. В архиве файлы проектов дли VС++, CodeBlocks, QtCreator. Причем программы, созданные VC++ и QtCreator, выводят этот дополнительный символ в консоль, а CodeBlocks - нет.
    Прикреплённый файлПрикреплённый файлcppLearning.zip (3,01 Кбайт, скачиваний: 23)
      Ну так у тебя p постинкрементится, чтобы в начале следующей итерации указывать на очередной свободный символ, но когда цикл завершается, это свободное место не используется, и там остаётся мусор. Замени, например, на прединкремент, чтобы позиция свободного символа вычислялась на текущей итерации, а не предыдущей.
      ExpandedWrap disabled
          p += size;
          for (int i = size - 1; i >= 0; i--)
          {
            *--p = (source & 1) + '0'; // '0' - 48 '1' - 49  printf("%p\n", buffer);
            source >>= 1;
          }
        Спасибо большое за ответ. Так получилось. Но возникли следующие вопросы:
        1. Почему в первой функции такого не происходит? Из-за фиксированного размера буфера?
        2. В строке *--p = (source & 1) + '0' или в строке p[size] = '\0'; появляется предупреждение VC++ "Разыменование пустого указателя, но все работает нормально. Что нужно сделать, чтобы это предупреждение исчезло?
        Сообщение отредактировано: tumanovalex -
          Разобрался по своему глупому 1 вопросу - потому что не возвращаю указатель. Если его возвращать, то результат тот же самый. А вот по вопросу № 2 не разобрался.
            Формально malloc() может вернуть NULL. Подозреваю, что ему не нравится тот факт, что нет на это поверки

            Добавлено
            P.S. Вторая функция в целом плохо спроектирована. Во-первых, динамический буфер от malloc() должен освобождаться. Помимо того, что я нигде не вижу free(), а увидеть я его мог бы только на вызывающей стороно, т.е. в данном случае в main(), так ещё и вызываемому коду неоткуда взять параметр для free(), т.к. ей приходит не тот же указатель, что вернула malloc(), а насколько-то там увеличенный.
            Сообщение отредактировано: Qraizer -
              Переделал функции:
              ExpandedWrap disabled
                template <class T> void TypeToBin1(T source, char* buffer, int size)
                {
                  buffer += size;
                  for (int i = size - 1; i >= 0; i--)
                  {
                    *--buffer = (source & 1) + '0'; // '0' - 48 '1' - 49  printf("%p\n", buffer);
                    source >>= 1;
                  }
                }
                 
                template <class T> void TypeToBin2(T source, char* buffer, int size)
                {
                  for (int i = size - 1; i >= 0; i--)
                  {
                    buffer[i] = (source & 1) + '0';
                    source >>= 1;
                  }
                }
              Функции работают нормально. Но хотелось бы сделать так, чтобы в функцию передавать только source, размер типа и буфер создавать в функции и иметь возможность содержимое буфера передавать вызывающей стороне, что-то типа такого:
              ExpandedWrap disabled
                template <class T> char* TypeToBin3(T source)
                {
                  int const size = 8 * sizeof(T);
                  char buffer[size + 1];
                  buffer[size] = '\0';
                  for (int i = size - 1; i >= 0; i--)
                  {
                    buffer[i] = (source & 1) + '0';
                    source >>= 1;
                  }
                  return buffer;
                }
              В таком виде printf("TypeToBin3 a = %s\n", TypeToBin3(a)) не возвращает правильное содержимое буфера. Подскажите, пожалуйста, как правильно вернуть содержимое буфера, созданного в функции (если это вообще возможно).

              Добавлено
              Я имел ввиду буфер, который не создается в динамической памяти

              Добавлено
              Цитата Qraizer @
              Формально malloc() может вернуть NULL. Подозреваю, что ему не нравится тот факт, что нет на это поверки

              Добавлено
              P.S. Вторая функция в целом плохо спроектирована. Во-первых, динамический буфер от malloc() должен освобождаться. Помимо того, что я нигде не вижу free(), а увидеть я его мог бы только на вызывающей стороно, т.е. в данном случае в main(), так ещё и вызываемому коду неоткуда взять параметр для free(), т.к. ей приходит не тот же указатель, что вернула malloc(), а насколько-то там увеличенный.

              А как правильно это делается? Надо передавать буфер и параметры, созданные вызывающей стороной? Чтобы она их и освободила?
                Цитата tumanovalex @
                Функции работают нормально. Но хотелось бы сделать так, чтобы в функцию передавать только source, размер типа и буфер создавать в функции и иметь возможность содержимое буфера передавать вызывающей стороне, что-то типа такого:
                ...
                В таком виде printf("TypeToBin3 a = %s\n", TypeToBin3(a)) не возвращает правильное содержимое буфера. Подскажите, пожалуйста, как правильно вернуть содержимое буфера, созданного в функции (если это вообще возможно)
                Естественно неправильно. Тут buffer[] является локальным автоматическим объектом, чьё время жизни заканчивается на return, т.ч. возвращаемый указатель указывает в никуда.
                На предмет того, чтобы сделать всё правильно, вариантов уйма, и все в той или иной степени подойдут или нет в зависимости от предпочтений. Основная идея – у буфера должен быть владелец.
                1. Внешний владелец – вызывающий код. Он его создаёт, он его освобождает, когда посчитает нужным, он указывает, куда помещать результат. Так работает TypeToBin1(). Но так тебе неудобно.
                2. Внутренний владелец – вызываемый код. Он создаёт буфер нужного размера, заполняет его результатом, но удалить его не может, т.к. он нужен вызывающему. Значит он должен передать владение ему, и далее вызывающий будет решать, когда его удалять. Так работает TypeToBin2(), но неправильно.
                3. Владельцем является сам буфер, и он сам знает, когда уничтожиться. Тут не обойтись без того, чтобы спроектировать архитектуру такого буфера и реализовать её. Обычно, раз у тебя C++, разумнее всего сделать сие классом.
                Вылечить TypeToBin2() несложно, нужно лишь возвращать результат malloc(), а не какой-то другой, и тогда вызывающий код легко сделает free(), когда ему будет удобно. Это означает, что TypeToBin2() придётся переместить результат к началу буфера, чтобы впереди не было мусора. Но если уж говорить за третий вариант, то у нас уже есть готовые владельцы, например std::vector<> или std::string, так что своего ничего писать не обязательно. Например:
                ExpandedWrap disabled
                  template <class T> std::string TypeToBin3(T source)
                  {
                    int const size = 8 * sizeof(T);
                    std::string p(size, ' ');
                   
                    for (int i = size - 1; i >= 0; i--)
                    {
                      p[i] = (source & 1) + '0';
                      source >>= 1;
                    }
                    return p;
                  }
                std::string сам владеет своим буфером, умеет им управлять и знает, когда его нужно освобождать: когда он сам разрушается. Примерно то же будет с std::vector<char>. Вообще, я давно забыл, когда ловил баги утечки памяти, просто никогда не использую ни malloc()/free(), ни new/delete. Классы, владеющие своими буферами, всё делают за меня и не ошибаются.
                  Спасибо большое за подробные объяснения и код!
                    Дополнил код считыванием и установкой битов:
                    ExpandedWrap disabled
                      #include <string>
                       
                      template <class T> std::string TypeToBin(T source)
                      {
                        int const size = 8 * sizeof(T);
                        std::string str(size, ' ');
                       
                        for (int i = size - 1; i >= 0; i--)
                        {
                          str[i] = (source & 1) + '0';
                          source >>= 1;
                        }
                        return str;
                      }
                       
                      template <class T> int GetBit(T source, int nBitNumber)
                      {
                        int mask = 1 << nBitNumber;
                        source = mask & source;
                        if(source)
                          return 1;
                        else
                          return 0;
                      }
                       
                      template <class T> T SetBit(T source, int nBit, int nBitValue)
                      {
                        int mask = 1 << nBit;
                        if (nBitValue == 0)
                        {
                          mask = ~mask;
                          source = source & mask;
                        }
                        else
                        {
                          source = source | mask;
                        }
                        return source;
                      }
                       
                      int main()
                      {
                        //char a = 'a';
                       //int a = 257;
                        short a = -257;
                        int nBit = 15;
                        int nBitValue = 0;
                        printf("GetBit%d = %d\n", nBit, GetBit(a, nBit));
                        printf("TypeToBin a  = %s\n", TypeToBin(a).c_str());
                        short res = SetBit(a, nBit, nBitValue);
                        printf("res = %d\n", res);
                        printf("GetBit%d = %d\n", nBit, GetBit(res, nBit));
                        printf("TypeToBin a2 = %s\n", TypeToBin(res).c_str());
                        system("pause");
                        return EXIT_SUCCESS;
                    Буду благодарен за любые замечания и предложения. Возник вопрос: можно ли сделать так, чтобы переменная res в main, которой присваивается результат SetBit, зависела от типа первого параметра этой функции? А то при изменении типа анализируемой переменной каждый раз придется изменять и тип переменной res. Проект прикрепил.
                    Прикреплённый файлПрикреплённый файлcppLearning.zip (3,56 Кбайт, скачиваний: 26)
                      Цитата tumanovalex @
                      Возник вопрос: можно ли сделать так, чтобы переменная res в main, которой присваивается результат SetBit, зависела от типа первого параметра этой функции?

                      Можно. Вот так
                      ExpandedWrap disabled
                        int main()
                        {
                          //char a = 'a';
                         //int a = 257;
                          short res, a = -257;
                          int nBit = 15;
                          int nBitValue = 0;
                          printf("GetBit%d = %d\n", nBit, GetBit(a, nBit));
                          printf("TypeToBin a  = %s\n", TypeToBin(a).c_str());
                          res = SetBit(a, nBit, nBitValue);
                          printf("res = %d\n", res);
                          printf("GetBit%d = %d\n", nBit, GetBit(res, nBit));
                          printf("TypeToBin a2 = %s\n", TypeToBin(res).c_str());
                          system("pause");
                          return EXIT_SUCCESS;
                        }
                        Спасибо! Как я сам не сообразил!
                          Цитата tumanovalex @
                          Буду благодарен за любые замечания и предложения
                          Работает – и ладно. Я б не так писал. Например, SetBit() используется для установки бита в указанное значение, однако мы привыкли, что установка бита – это конкретно в 1, а если в 0, то это сброс бита. Поэтому интуитивнее видеть не одну функцию, а две setBit() и clearBit() и без указания значения, и так понятно, для какой какое. Или вот GetBit() формально возвращает значение бита, поэтому 0 или 1 понятно. Но мы привыкли, что бит либо взведён либо сброшен, поэтому вместо получения значения и сравнения с чем-то там, просто спрашиваем, взведён ли, и в ответ получаем bool. Но это на любителя.
                          Но вот что не на любителя... попробуй передать отрицательный номер бита или с большим значением, например, 57. По Стандарту это неопределённое поведение, так что результаты могут удивить. Или вот смешивание C и C++. Зачем printf(), если есть std::cout? А недавно нам Python-овый format() завезли, так вааще лафа.
                          Цитата tumanovalex @
                          Возник вопрос: можно ли сделать так, чтобы переменная res в main, которой присваивается результат SetBit, зависела от типа первого параметра этой функции?
                          std::any. Некое подобие динамической типизации. Не совсем, но очень похоже: в него можно положить всё, и он помнит, какой тип в него положен, однако при чтении нужно самому знать, что там. Нельзя положить, скажем int, а вытащить строку, бросит эксепшн. Ниже примерный код, основанный на decltype. Тоже очень удобная вещь, но статическая, в динамике тип не определяет.
                          ExpandedWrap disabled
                            int main()
                            {
                              char b = 'a';
                              int  c = 257;
                              short a = -257;
                              int nBit1 = 15;
                              int nBit2 = 0;
                              int nBitValue1 = 0;
                              int nBitValue2 = 1;
                             
                              printf("GetBit%d = %d\n", nBit1, GetBit(a, nBit1));
                              printf("TypeToBin a  = %s\n", TypeToBin(a).c_str());
                             
                              std::any res = SetBit(a, nBit1, nBitValue1);
                             
                              printf("res = %d\n", std::any_cast<decltype(a)>(res));
                              printf("GetBit%d = %d\n", nBit1, GetBit(std::any_cast<decltype(a)>(res), nBit1));
                              printf("TypeToBin a2 = %s\n", TypeToBin(std::any_cast<decltype(a)>(res)).c_str());
                             
                              printf("GetBit%d = %d\n", nBit2, GetBit(b, nBit2));
                              printf("TypeToBin b  = %s\n", TypeToBin(b).c_str());
                              res = SetBit(b, nBit2, nBitValue1);
                              printf("res = %d\n", std::any_cast<decltype(b)>(res));
                              printf("GetBit%d = %d\n", nBit2, GetBit(std::any_cast<decltype(b)>(res), nBit2));
                              printf("TypeToBin b2 = %s\n", TypeToBin(std::any_cast<decltype(b)>(res)).c_str());
                             
                              printf("GetBit%d = %d\n", nBit1, GetBit(c, nBit1));
                              printf("TypeToBin c  = %s\n", TypeToBin(c).c_str());
                              res = SetBit(c, nBit1, nBitValue2);
                              printf("res = %d\n", std::any_cast<decltype(c)>(res));
                              printf("GetBit%d = %d\n", nBit1, GetBit(std::any_cast<decltype(c)>(res), nBit1));
                              printf("TypeToBin c2 = %s\n", TypeToBin(std::any_cast<decltype(c)>(res)).c_str());
                             
                              system("pause");
                              return EXIT_SUCCESS;
                            }
                          Посмотри, мож получится применить.
                          Сообщение отредактировано: Qraizer -
                            Цитата tumanovalex @
                            можно ли сделать так, чтобы переменная res в main, которой присваивается результат SetBit, зависела от типа первого параметра этой функции?

                            Есть вариант, как если вместо std::any использовать auto. Вот переписанный вариант от Qraizer:

                            ExpandedWrap disabled
                              int main()
                              {
                                  char b = 'a';
                                  int  c = 257;
                                  short a = -257;
                                  int nBit1 = 15;
                                  int nBit2 = 0;
                                  int nBitValue1 = 0;
                                  int nBitValue2 = 1;
                               
                                  printf("GetBit%d = %d\n", nBit1, GetBit(a, nBit1));
                                  printf("TypeToBin a  = %s\n", TypeToBin(a).c_str());
                               
                                  auto res1 = SetBit(a, nBit1, nBitValue1);
                               
                                  printf("res = %d\n", res1);
                                  printf("GetBit%d = %d\n", nBit1, GetBit(res1, nBit1));
                                  printf("TypeToBin a2 = %s\n", TypeToBin(res1).c_str());
                                  printf("GetBit%d = %d\n", nBit2, GetBit(b, nBit2));
                                  printf("TypeToBin b  = %s\n", TypeToBin(b).c_str());
                               
                                  auto res2 = SetBit(b, nBit2, nBitValue1);
                               
                                  printf("res = %d\n", res2);
                                  printf("GetBit%d = %d\n", nBit2, GetBit(res2, nBit2));
                                  printf("TypeToBin b2 = %s\n", TypeToBin(res2).c_str());
                                  printf("GetBit%d = %d\n", nBit1, GetBit(c, nBit1));
                                  printf("TypeToBin c  = %s\n", TypeToBin(c).c_str());
                               
                                  auto res3 = SetBit(c, nBit1, nBitValue2);
                               
                                  printf("res = %d\n", res3);
                                  printf("GetBit%d = %d\n", nBit1, GetBit(res3, nBit1));
                                  printf("TypeToBin c2 = %s\n", TypeToBin(res3).c_str());
                               
                                  system("pause");
                                  return EXIT_SUCCESS;
                              }

                            Преимущество: auto - явно даёт более "легкий" код по сравнению с std::any.
                            Недостаток: если переменную, объявленную как auto, "переиспользовать", то можно ожидать сюрпризы, т.к. она получает тип только в момент объявления, а std::any помнит тип и в процессе переинициализации. Поэтому в своем примере я вынужден был объявлять три разных переменных, и переинициализацию не использовать.

                            Ну и вдогоночку замечания, почему так работу с битами лучше не делать:

                            1) При последовательном вызове SetBit, GetBit, TypeOfBin очень легко можно перепутать имена переменных, и очень часто это не приведёт к ошибке времени компиляции. А при выполнении будут ошибочные данные. Для этого и придумали инкапсуляцию от ООП. И она часто помогает в таких случаях. Оформляй это классом, а функции оформляй методами.
                            2) Установка, чтение и печать битов более-менее подойдет только для POD-типов. А вот представь, что ты в качестве источника используешь указатель, к примеру, на 64кб массив char. Хана твоей логике. Для того, чтобы это не случилось - тебе нужно написать метод побайтного доступа к той переменной, с которой будет работать твой класс. Подчеркиваю, только метод доступа - содержимое самой этой переменной дублировать не следует.
                            3) Индексы установки/чтения битов в методах нужно сразу проверять на выходы за допустимые пределы, иначе будет лабуда!
                              ADD:

                              tumanovalex, если в качестве теста/обучения - нет проблем, экспериментируй. Но если хочется чего-то более предметного, что можно включать в свои проекты - то лучше не изобретать велосипед, а воспользоваться уже готовыми решениями из STL. Вот небольшой примерчик (ИСПРАВЛЕНО):

                              ExpandedWrap disabled
                                #include <iostream>
                                #include <bitset>
                                #include <array>
                                 
                                int main() {
                                    // Создаем массив char размером 16 и инициализируем его
                                    std::array<unsigned char, 16> byteArray = {0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x01};
                                 
                                    // Создаем bitset, используя массив
                                    std::bitset<128> bits;
                                    for (size_t i = 0; i < byteArray.size(); ++i) {
                                        bits <<= 8;
                                        bits |= byteArray[i];
                                    }
                                 
                                    // Устанавливаем 3-й и предпредпоследний биты
                                    bits.set(2);
                                    bits.set(125);
                                 
                                    // Выводим результат
                                    std::cout << bits << std::endl;
                                 
                                    return 0;
                              Сообщение отредактировано: Majestio -
                                Спасибо, Qraiser и Majestio, за объяснения и код!
                                  Majestio, ты что-то путаешь. У std::bitset<> нет конструктора, принимающего массив байт. Его конструкторы, принимающие строки в том или ином виде, как обозначение бита рассматривают каждый символ, а не бит. Т.е. можно получить std::bitset<8>("00110110").to_ulong() == 0b110110ul (или std::bitset<8>(0b110110ul).to_string() == "00110110"), но не или std::bitset<8>("01").to_ulong() == 0b00000001ul
                                    Qraizer, да - всё верно! Перепутал я малёха. Свой пример с std::bitset я исправил.
                                      tumanovalex, кстати, я тоже когда-то делал для себя заготовки для работы с битами без STL - ознакомься :) Правда там есть два недостатка: нет проверок индекса на предмет выхода за пределы массива, и нет определения порядка битов в байте для целевой архитектуры. Но это уже всё можно добавить, при желании.
                                        В общем, если кому интересно, то универсальный код преобразования обоих типов ...э-э-э, типов в битовый вид.
                                        ExpandedWrap disabled
                                          #include <limits>
                                          #include <concepts>
                                          #include <cmath>
                                          #include <bit>
                                           
                                          /* преобразование целых в строку */
                                          std::string TypeToBin(std::integral auto source)
                                          {
                                            int const   size = std::numeric_limits<unsigned char>::digits * sizeof(source);       // размер в битах
                                            std::string str(size, ' ');
                                           
                                            for (int i = size - 1; i >= 0; i--)
                                            {
                                              str[i] = (source & 1) + '0';
                                              source >>= 1;
                                            }
                                            return str;
                                          }
                                           
                                          /* преобразование вещественных в строку (для не IEEE-совместимых не тестировалось) */
                                          std::string TypeToBin(std::floating_point auto source)
                                          {
                                            std::string    buf;
                                            int            power;                 // порядок source
                                            const auto    &properties   = std::numeric_limits<decltype(source)>{};
                                            const unsigned shiftedPower = static_cast<unsigned>(properties.max_exponent - properties.min_exponent);
                                           
                                            buf.reserve(properties.digits + std::bit_width(shiftedPower) + 3);   // + точка, 'b' и знак
                                            buf = std::signbit(source) + '0';     // первым знак
                                            if (!std::isfinite(source))           // проверка на спец.форматы NaN и inf
                                            {
                                              // сначала избавиться от порядка, но сохранить мантиссу (на случай NaN особенно)
                                              // используем бесконечность как образец в памяти ...
                                              decltype(source) pattern = properties.infinity();
                                              const char (&nanByte)[sizeof(pattern)] = reinterpret_cast<const char (&)[sizeof(pattern)]>(pattern);
                                                    char (&srcByte)[sizeof(source)]  = reinterpret_cast<      char (&)[sizeof(source)]> (source);
                                           
                                              // ... и обрабатываем source побайтно, стирая порядок ...
                                              for (int i = 0; i < sizeof(nanByte); ++i)
                                                srcByte[i] ^= nanByte[i];
                                              // ... а затем заменяем его на несмещённый порядок 0
                                              // это также учтёт явный старший бит, если он есть, т.к. XOR применяется дважды
                                              // + нам пофик на endianess, т.к. он одинаковый для source и pattern
                                              pattern = 1;
                                              for (int i = 0; i < sizeof(nanByte); ++i)
                                                srcByte[i] ^= nanByte[i];
                                              source = abs(source);               // теперь можно вычислять модуль, в source не спец.формат
                                              // максимальный порядок спец.форматов с учётом его разрядности в типе source, т.к. реализации
                                              // любят в FP_ILOGBNAN совать просто MAX_INT
                                              power = FP_ILOGBNAN & (std::bit_ceil(shiftedPower) - 1);
                                            }
                                            else                                  // для остальных форматов всё значительно проще
                                            {
                                              source = abs(source);               // модуль можно сразу
                                              power = logb(source);               // порядок
                                              source= ldexp(source, -power);      // чистая мантисса (с порядком 0)
                                              // использовать frexp() нежелательно, т.к. она возвращает мантиссу, сдвинутую в [0.5, 1)
                                              // что уменьшает точность на бит и требует специальной дополнительной обработки её и порядка,
                                              // особенно рядом с std::numeric_limits<>::denorm_min()
                                            }
                                            /* обработать мантиссу */
                                            for (int i = 0; i < properties.digits; ++i)
                                            {
                                              buf       += static_cast<char>(static_cast<int>(source));
                                              source    -= buf.back();
                                              buf.back()+= '0';
                                              source    *= static_cast<decltype(source)>(2);
                                            }
                                            buf.insert(2, 1, '.');                // добавить точку в buf
                                           
                                            // обработать порядок
                                            buf += 'b';
                                            // power хранит меньшую разрядность, чем способен его тип, например 12 для IEEEшного double,
                                            // поэтому имеет смысл отрезать от него только нужное количество младших бит
                                            buf += TypeToBin(power).substr(std::numeric_limits<decltype(power)>::digits - 1 // знак уже учтён
                                                                         - std::bit_width(shiftedPower / 2));             // а порядок смещён
                                           
                                            return buf;
                                          }
                                        Требует C++20. Вид битового ...э-э-э, вида вещественных сомнителен. Мне тоже не нравится, но так единообразнее с видом целых. Кому интересно переделать, милости прошу. Знак вещественного просто 0 или 1, знак порядка аналогично. Точка в мантиссе соответственно лежит после второго бита. Мантиссы спец.форматов по возможности разгребаются, но хорошо потестировать поленился. Бесконечности и нечисла распознаются по старшим 011 в порядке, отличаются друг от друга естественно мантиссой. Знаки также распознаются правильно, даже для нуля.
                                        Сообщение отредактировано: Qraizer -
                                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                        0 пользователей:


                                        Рейтинг@Mail.ru
                                        [ Script execution time: 0,0654 ]   [ 20 queries used ]   [ Generated: 16.06.25, 19:14 GMT ]