Ответ 1
У меня это было в первый раз, за исключением того, что мне было нужно ntohl... C Endian Conversion: по-бит
Я пытаюсь создать симулятор конвейера команд, и у меня возникли проблемы с запуском. То, что мне нужно сделать, это прочитать двоичный файл из stdin, а затем сохранить его в памяти, пока я манипулирую данными. Мне нужно читать куски ровно 32 бита один за другим.
Как читать в кусках ровно 32 бита за раз? Во-вторых, как сохранить его для манипуляции позже?
Вот то, что у меня есть до сих пор, но изучая бинарные куски, которые я читаю дальше, это просто не выглядит правильным, я не думаю, что читаю ровно 32 бита, как мне нужно.
char buffer[4] = { 0 }; // initialize to 0
unsigned long c = 0;
int bytesize = 4; // read in 32 bits
while (fgets(buffer, bytesize, stdin)) {
memcpy(&c, buffer, bytesize); // copy the data to a more usable structure for bit manipulation later
// more stuff
buffer[0] = 0; buffer[1] = 0; buffer[2] = 0; buffer[3] = 0; // set to zero before next loop
}
fclose(stdin);
Как я могу читать по 32 бита за раз (все они 1/0, нет строк и т.д.), и что я храню в нем, char[]
okay?
EDIT: я могу прочитать двоичный файл, но ни один из ответов не порождает биты в правильном порядке - все они искалечены, я подозреваю, что суждение и проблемы с чтением и перемещением 8 бит вокруг (1 char) в то время - это нужно для работы с Windows и C...?
У меня это было в первый раз, за исключением того, что мне было нужно ntohl... C Endian Conversion: по-бит
Вам нужно freopen()
. С manpage:
Если filename является нулевым указателем, функция freopen() должна попытаться изменить режим потока на режим, указанный режимом, как если бы использовалось имя файла, связанного с потоком. В этом случае дескриптор файла, связанный с потоком, не нужно закрывать, если вызов функции freopen() завершается успешно. Определяется реализация, какие изменения режима разрешены (если есть) и при каких обстоятельствах.
В принципе, лучшее, что вы действительно можете сделать, это следующее:
freopen(NULL, "rb", stdin);
Это приведет к повторному открытию stdin
того же входного потока, но в двоичном режиме. В обычном режиме чтение из stdin
в Windows преобразует \r\n
(Windows newline) в один символ ASCII 10. Использование режима "rb"
отключает это преобразование, чтобы вы могли правильно читать в двоичных данных.
freopen()
возвращает дескриптор файла, но это предыдущее значение (прежде чем мы поместим его в двоичном режиме), поэтому не используйте его ни для чего. После этого используйте fread()
, как было упомянуто.
Что касается ваших проблем, вы можете не читать "32 бита", но если вы используете fread()
, вы будете читать в 4 char
(это лучшее, что вы можете сделать в C - char
гарантируется как минимум 8 бит, но некоторые исторические и встроенные платформы имеют 16 бит char
(некоторые даже имеют 18 или хуже)). Если вы используете fgets()
, вы никогда не будете читать в 4 байта. Вы будете читать как минимум 3 (в зависимости от того, является ли какая-либо из них символами новой строки), а 4-й байт будет '\0'
, потому что строки C имеют nul-terminated и fgets()
nul-завершает то, что он читает (например, хорошая функция), Очевидно, это не то, что вы хотите, поэтому вы должны использовать fread()
.
Рассмотрим использование макроса SET_BINARY_MODE
и setmode
:
#ifdef _WIN32
# include <io.h>
# include <fcntl.h>
# define SET_BINARY_MODE(handle) setmode(handle, O_BINARY)
#else
# define SET_BINARY_MODE(handle) ((void)0)
#endif
Подробнее о макросе SET_BINARY_MODE
здесь: " Обработка двоичных файлов через стандартный ввод-вывод"
Подробнее о setmode
здесь: _ setmode"
fgets() здесь не так. Он нацелен на текст, читаемый человеком, ASCII, который заканчивается символами конца строки, а не двоичными данными, и не получит вас, что вам нужно.
Недавно я сделал именно то, что вы хотите, используя вызов read(). Если ваша программа явно закрыла stdin, для первого аргумента (дескриптор файла) вы можете использовать постоянное значение 0 для stdin. Или, если вы находитесь в системе POSIX (Linux, Mac OS X или какой-либо другой современный вариант Unix), вы можете использовать STDIN_FILENO.
Я не знаю, какую ОС вы используете, но вы обычно не можете "открывать stdin в двоичном формате". Вы можете попробовать что-то вроде
int fd = fdreopen (fileno (stdin), outfname, O_RDONLY | OPEN_O_BINARY);
чтобы попытаться заставить его. Затем используйте
uint32_t opcode;
read(fd, &opcode, sizeof (opcode));
Но я сам этого не пробовал.:)
fread() лучше всего подходит для чтения двоичных данных.
Да, массив char в порядке, если вы планируете их обрабатывать по очереди.