На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Универсальная функция перевода в двоичное представление на чистом С
    Здравствуйте!
    На киберфоруме была предложена функция перевода в двоичное представление на чистом C:
    ExpandedWrap disabled
      #include <stdio.h>
      #include <stdlib.h>
      #include <stdint.h>
       
      char* void2bin(void* data, size_t size)
      {
        char* dest = (char*)malloc(1 + 8 * size);
        char* ptr = dest;
        uint8_t* b = (uint8_t*)(data)+size - 1;
       
        for (size_t bit = 8 * size; bit--; ptr++)
        {
          *ptr = (*b & (1 << (bit & 7))) ? '1' : '0';
          if (!(bit % 8)) b--;
        }
       
        dest[8 * size] = 0;
        return dest;
      }
       
      int main()
      {
        //char a = 'a';
        //int a = 255;
        long long int a = 0xFFFFFFFFFFFFFFFF;
        char* bin_res = void2bin(&a, sizeof(a));
        printf("a = %s\n", bin_res);
        free(bin_res);
        char ch = _getch();
        return 0;
      }
    Я проверил для нескольких типов файлов, работает. Как я понял, благодаря void* и введению дополнительных указателей b и ptr удалось в операциях с битами обойтись только указателями и не использовать тип данных в операциях с битами. Мне более понятен код с индексами, я попытался:
    ExpandedWrap disabled
      void TypeToBin(void* data, size_t size)
      {
        char* dest = (char*)malloc(1 + 8 * size);
        for (int i = size - 1; i >= 0; i--)
        {
          dest[i] = (*data & 1) + '0'; // ошибка
          *data >>= 1; // ошибка
        }
        dest[8 * size] = 0;
        return dest;
      }
    но ожидаемо получил ошибки в разиименованиях. Подскажите, пожалуйста, можно ли как-то попроще (понятнее) сделать подобную универсальную программу. Проект прикрепил.
    Прикреплённый файлПрикреплённый файлcLearning.zip (2,82 Кбайт, скачиваний: 14)
      Разименовывать void* нельзя. *data - ошибочное выражение, т.к. нельзя создать переменную типа void.
      Если хотите так, то используйте char*

      Ну и вашей версии принципиальная ошибка. data >>= 1 никак не вяжется с циклом, т.к. цикл у вас по байтам.
      То есть вы фактически преобразуете только младший бит каждого байта.
        Цитата tumanovalex @
        но ожидаемо получил ошибки в разиименованиях.

        Внимательно изучи работающий пример.
        Почему там нет ошибок, а у тебя есть ?
        Вот это:
        ExpandedWrap disabled
          ...uint8_t*)(data) ...
          tumanovalex, при обработке больших данных, и если критична скорость обработки, лучше использовать вот такой подход (тут без контроля ошибки по выделению памяти):

          ExpandedWrap disabled
            #include <stdio.h>
            #include <stdlib.h>
            #include <stdint.h>
            #include <string.h>
             
            // Таблица для преобразования байта в его строковое представление
             
            static const char* const lut[256] = {
              "00000000", "00000001", "00000010", "00000011",  "00000100", "00000101", "00000110", "00000111",
              "00001000", "00001001", "00001010", "00001011",  "00001100", "00001101", "00001110", "00001111",
              "00010000", "00010001", "00010010", "00010011",  "00010100", "00010101", "00010110", "00010111",
              "00011000", "00011001", "00011010", "00011011",  "00011100", "00011101", "00011110", "00011111",
              "00100000", "00100001", "00100010", "00100011",  "00100100", "00100101", "00100110", "00100111",
              "00101000", "00101001", "00101010", "00101011",  "00101100", "00101101", "00101110", "00101111",
              "00110000", "00110001", "00110010", "00110011",  "00110100", "00110101", "00110110", "00110111",
              "00111000", "00111001", "00111010", "00111011",  "00111100", "00111101", "00111110", "00111111",
              "01000000", "01000001", "01000010", "01000011",  "01000100", "01000101", "01000110", "01000111",
              "01001000", "01001001", "01001010", "01001011",  "01001100", "01001101", "01001110", "01001111",
              "01010000", "01010001", "01010010", "01010011",  "01010100", "01010101", "01010110", "01010111",
              "01011000", "01011001", "01011010", "01011011",  "01011100", "01011101", "01011110", "01011111",
              "01100000", "01100001", "01100010", "01100011",  "01100100", "01100101", "01100110", "01100111",
              "01101000", "01101001", "01101010", "01101011",  "01101100", "01101101", "01101110", "01101111",
              "01110000", "01110001", "01110010", "01110011",  "01110100", "01110101", "01110110", "01110111",
              "01111000", "01111001", "01111010", "01111011",  "01111100", "01111101", "01111110", "01111111",
              "10000000", "10000001", "10000010", "10000011",  "10000100", "10000101", "10000110", "10000111",
              "10001000", "10001001", "10001010", "10001011",  "10001100", "10001101", "10001110", "10001111",
              "10010000", "10010001", "10010010", "10010011",  "10010100", "10010101", "10010110", "10010111",
              "10011000", "10011001", "10011010", "10011011",  "10011100", "10011101", "10011110", "10011111",
              "10100000", "10100001", "10100010", "10100011",  "10100100", "10100101", "10100110", "10100111",
              "10101000", "10101001", "10101010", "10101011",  "10101100", "10101101", "10101110", "10101111",
              "10110000", "10110001", "10110010", "10110011",  "10110100", "10110101", "10110110", "10110111",
              "10111000", "10111001", "10111010", "10111011",  "10111100", "10111101", "10111110", "10111111",
              "11000000", "11000001", "11000010", "11000011",  "11000100", "11000101", "11000110", "11000111",
              "11001000", "11001001", "11001010", "11001011",  "11001100", "11001101", "11001110", "11001111",
              "11010000", "11010001", "11010010", "11010011",  "11010100", "11010101", "11010110", "11010111",
              "11011000", "11011001", "11011010", "11011011",  "11011100", "11011101", "11011110", "11011111",
              "11100000", "11100001", "11100010", "11100011",  "11100100", "11100101", "11100110", "11100111",
              "11101000", "11101001", "11101010", "11101011",  "11101100", "11101101", "11101110", "11101111",
              "11110000", "11110001", "11110010", "11110011",  "11110100", "11110101", "11110110", "11110111",
              "11111000", "11111001", "11111010", "11111011",  "11111100", "11111101", "11111110", "11111111"
            };
             
            char* void2bin(void* data, size_t size) {
              char* dest = (char*)malloc(1 + 8 * size);
              char* ptr = dest;
              uint8_t* bytes = (uint8_t*)data;
              for (size_t i = 0; i < size; i++) {
                memcpy_s(ptr, 8, lut[bytes[size - 1 - i]], 8);
                ptr += 8;
              }
              * ptr = '\0';
              return dest;
            }
             
            int main() {
              long long int a = 0x01FFFFFFFFFFFFFF;
              char* bin_res = void2bin( & a, sizeof(a));
              printf("a = %s\n", bin_res);
              free(bin_res);
              return 0;
            }

          Да, и еще лучше не дергать выделение памяти в самой функции, а передавать указатель на уже заранее выделенный участок памяти для строкового представления. Ну или сделать дубль функции с внешним выделением. Вдруг придется переводить в двоично-строковое представление данные из таблицы со 100500 элементов ... ну не дёргать же память 100500 раз?
            Иногда я думаю, ну зачем учить людей Cям, когда есть C++?..
            ExpandedWrap disabled
              constexpr std::string TypeToBin(const auto& x)
              {
                return std::bitset<sizeof(x)*8>(x).to_string();
              }
              Majestio и Qraizer, спасибо большое за объяснения и код!
                tumanovalex, помимо сказанного grgdvo и ЫукпШ, твоя функция не умеет принимать литералы, ей нельзя скормить константы, а главное – обнуляет свой параметр. Очень недальновидное архитектурное решение.
                А кроме того, пример, который тебе кинули, плох. На киберфоруме, видать, сидят те ещё косяпоры, раз даже не предупредили тебя, что работать этот код будет только на little-endian платформах. Ну и положа руку на сердце, не везде байт восьмибитный.
                ExpandedWrap disabled
                  #include <limits.h>
                  #include <stdbit.h>
                   
                  #if __STDC_ENDIAN_NATIVE__ != __STDC_ENDIAN_LITTLE__ && __STDC_ENDIAN_NATIVE__ != __STDC_ENDIAN_BIG__
                  #error Endianness has unknown format
                  #endif
                   
                  char* TypeToBin(const void* data, size_t size)
                  {
                    char *dest = (char*)malloc(1 + CHAR_BIT*size),
                         *value= (char*)data;
                    int  toNext= 1;
                   
                  #if __STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_LITTLE__
                    value += size - 1;
                    toNext =-1;
                  #endif
                   
                    for (int j = 0; j < size; ++j)
                    {
                      unsigned char byte = *value;
                   
                      for (int i = CHAR_BIT-1; i >= 0; --i)
                      {
                        dest[j*CHAR_BIT + i] = (byte & 1) + '0';
                        byte >>= 1;
                      }
                      value += toNext;
                    }
                    dest[CHAR_BIT*size] = 0;
                   
                    return dest;
                  }
                Следует отметить, что это C23. Именно тут появился stdbit.h. Для более ранних версий макросы нужно либо задавать вручную, либо определять endianness в ран-тайм.

                Добавлено
                Что-то типа
                ExpandedWrap disabled
                  _Bool isLittle(void)
                  {
                    long long check = 1;
                    const char *ptr = (const char*)&​check;
                   
                    return *ptr == '\1';
                  }
                и заменить #if на обычный if(), но следует отметить, работать будет, только если sizeof(long long) > 1. Впрочем, если == 1, то на endianness вообще пофик
                Сообщение отредактировано: Qraizer -
                  Цитата Qraizer @
                  Иногда я думаю, ну зачем учить людей Cям, когда есть C++?..
                  ExpandedWrap disabled
                    constexpr std::string TypeToBin(const auto& x)
                    {
                      return std::bitset<sizeof(x)*8>(x).to_string();
                    }

                  Сам же попался на том, о чем меня поправлял в соседней теме :lool:
                  У чела в теме "универсальная" функция, а в объявлении char* void2bin(void* data, size_t size). Если в твою функцию подать к примеру char[256], твой конструктор битсета взмолится, максимум long long. Или строку из STL. Эх ты ;)
                    Универсальная функция не рассчитана на составные типы, да. Ну так у ТС то же самое. Самое время у него уточнить, конечно, а то мало ли. И даже при этом непонятно, как быть с вещественными. Добавь концепт std::integral, если хочешь.
                      Цитата Qraizer @
                      Ну так у ТС то же самое. Самое время у него уточнить, конечно, а то мало ли.
                      А кто такой ТС?
                        Ты :D . ТопикСтартер
                          Я имел ввиду отрицательные и положительные целые числа и char. Я думал, что получить битовое представление составных типов и вещественных чисел нельзя.
                            Можно, но смысла в этом немного. Особенно составных.
                              Цитата tumanovalex @
                              Я думал, что получить битовое представление составных типов и вещественных чисел нельзя.

                              Наводящий вопрос: Как же тогда их умудряется сохранять в памяти компьютер?
                              Но я согласен. Смысл печатать двоичное представление для вещественных или составных чисел нету. Шестнадцатеричное представление еще полезно, а вот двоичное уже точно нет.
                                Цитата macomics @
                                Наводящий вопрос: Как же тогда их умудряется сохранять в памяти компьютер?

                                :lol:
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0521 ]   [ 18 queries used ]   [ Generated: 1.06.25, 03:06 GMT ]