Использование побитовых операторов в C ++ для изменения 4 символов в int - PullRequest
5 голосов
/ 17 марта 2011

Что я должен сделать, это открыть файл в двоичном режиме, который содержит хранимые данные, которые предназначены для интерпретации как целые числа.Я видел другие примеры, такие как Stackoverflow-чтение «целочисленных» байтов из массива char *. , но я хочу попробовать другой подход (я могу быть просто упрямым или глупым: /).Сначала я создал простой двоичный файл в шестнадцатеричном редакторе, который выглядит следующим образом.

00 00 00 47 00 00 00 17 00 00 00 41
Это (должно) равняться 71, 23 и 65, если 12 байтов были разделены на 3 целых числа.

После открытия этого файла в двоичном режиме и чтения 4 байтовв массив символов, как я могу использовать побитовые операции, чтобы биты char [0] были первыми 8 битами целого и т. д., пока биты каждого символа не станут частью целого числа.

 
My integer = 00        00        00        00  
 +           ^         ^         ^         ^
Chars      Char[0]  Char[1]   Char[2]   Char[3]
             00        00        00        47


So my integer(hex) = 00 00 00 47 = numerical value of 71

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

Вот фрагмент кодаиз того, что у меня есть, я просто не знаю, что делать дальше.


std::fstream myfile;
    myfile.open("C:\\Users\\Jacob\\Desktop\\hextest.txt", std::ios::in | std::ios::out | std::ios::binary);
    if(myfile.is_open() == false)
    {
        std::cout &lt&lt "Error" &lt&lt std::endl;
    }
    char* mychar;
    std::cout &lt&lt myfile.is_open() &lt&lt std::endl;
    mychar = new char[4];
    myfile.read(mychar, 4);

В конце концов я планирую заняться чтением чисел с плавающей точкой из файла и, возможно, пользовательского типа данных, но сначала мне просто нужно больше ознакомиться с использованием побитовых операций.Спасибо.

Ответы [ 2 ]

20 голосов
/ 17 марта 2011

Требуется побитовый левый оператор сдвига:

typedef unsigned char u8;  // in case char is signed by default on your platform
unsigned num = ((u8)chars[0] << 24) | ((u8)chars[1] << 16) | ((u8)chars[2] << 8) | (u8)chars[3];

Что он делает, это смещает левый аргумент на указанное количество битов влево, добавляя нули справа в качестве начинки.Например, 2 << 1 равно 4, так как 2 равно 10 в двоичном виде, а смещение влево равно 100, что равно 4.

Это может быть записано в более общей форме цикла:

unsigned num = 0;
for (int i = 0; i != 4; ++i) {
    num |= (u8)chars[i] << (24 - i * 8);    // += could have also been used
}

Порядковый номер вашей системы здесь не имеет значения;Вы знаете порядок представления в файле, который является постоянным (и, следовательно, переносимым), поэтому, когда вы читаете в байтах, вы знаете, что с ними делать.Внутреннее представление целого числа в вашем процессоре / памяти может отличаться от представления файла, но логическое побитовое манипулирование им в коде не зависит от порядкового номера вашей системы;младшие значащие биты всегда справа, а большинство слева (в коде).Вот почему сдвиг является кроссплатформенным - он работает на логическом уровне битов: -)

2 голосов
/ 17 марта 2011

Задумывались ли вы об использовании Boost.Spirit для создания двоичного парсера? Когда вы начнете, вы можете немного пройтись по кривой обучения, но если вы захотите расширить свою программу позже, чтобы читать плавающие и структурированные типы, у вас будет отличная база для начала.

Дух очень хорошо задокументирован и является частью Boost. Как только вы поймете все, что вам нужно, все ошеломляет то, что вы можете с этим сделать, поэтому, если у вас есть немного времени, чтобы поиграть с этим, я действительно рекомендую взглянуть.

В противном случае, если вы хотите, чтобы ваш двоичный файл был «переносимым», т. Е. Вы хотите иметь возможность читать его на машинах с прямым и прямым порядком байтов, вам понадобится какая-то метка порядка байтов (BOM). ). Это будет первое, что вы прочтете, после чего вы можете просто прочитать ваши целые числа побайтно. Вероятно, проще всего было бы прочитать их в объединение (если вы знаете размер целого числа, которое вы собираетесь прочитать), например:

union U
{
    unsigned char uc_[4];
    unsigned long ui_;
};

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

НТН

1012 * RLC *

...