C读二进制stdin

时间:2009-10-21 06:04:31

标签: c binary stdin

我正在尝试构建一个指令管道模拟器,我在开始时遇到了很多麻烦。我需要做的是从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[]好吗?

编辑:我能够读取二进制文件,但没有一个答案以正确的顺序产生这些位 - 它们都被破坏了,我怀疑字节顺序和读取问题以及移动8位(1个字符)时间 - 这需要在Windows和C上工作......?

8 个答案:

答案 0 :(得分:22)

您需要的是freopen()。从联机帮助页:

  

如果filename是空指针,则freopen()函数将尝试将流的模式更改为mode指定的模式,就好像当前与流关联的文件的名称已被使用一样。在这种情况下,如果对freopen()的调用成功,则不需要关闭与流关​​联的文件描述符。它是实现定义的模式允许更改(如果有),以及在什么情况下。

基本上,你真正做的最好的就是:

freopen(NULL, "rb", stdin);

这将重新打开stdin作为相同的输入流,但是处于二进制模式。在正常模式下,从Windows上的stdin进行读取会将\r\n(Windows换行符)转换为单字符ASCII 10.使用"rb"模式会禁用此转换,以便您可以正确读取二进制数据。

freopen()返回一个文件句柄,但它是之前的值(在我们将它置于二进制模式之前),所以不要将它用于任何事情。之后,如前所述使用fread()

但是,关于您的担忧,您可能不会读取“32位”,但如果您使用fread(),则读取4 char s(其中是你在C中做的最好的 - char保证至少 8位但是一些历史和嵌入式平台有16位char s(有些甚至有18位或者更差))。如果您使用fgets(),则永远不会读取4个字节。您将读取至少3个(取决于它们中的任何一个是否为换行符),并且第4个字节将为'\0',因为C字符串是空终止的并且fgets() nul-终止它所读取的内容(如一个好的功能)。显然,这不是你想要的,所以你应该使用fread()

答案 1 :(得分:17)

考虑使用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宏的更多详情:“Handling binary files via standard I/O

此处setmode的更多详细信息:"_setmode

答案 2 :(得分:1)

fgets()在这里完全错了。它的目标是人类可读的ASCII文本,以行尾字符而非二进制数据终止,无法满足您的需求。

我最近使用read()调用完成了您想要的操作。除非您的程序已明确关闭stdin,否则对于第一个参数(文件描述符),您可以对stdin使用常量值0。或者,如果您使用的是POSIX系统(Linux,Mac OS X或其他一些现代Unix版本),则可以使用STDIN_FILENO。

答案 3 :(得分:1)

我不得不根据上述同仁的各种评论将答案拼凑在一起,因此这是一个可以正常工作的示例,仅适用于Windows,但您可以将Windows特定的东西翻译到您的平台上。 / p>

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
#include <io.h>
#include <fcntl.h>

int main()
{
    char rbuf[4096];
    char *deffile = "c:\\temp\\outvideo.bin";
    size_t r;
    char *outfilename = deffile;
    FILE *newin;

    freopen(NULL, "rb", stdin);
    _setmode(_fileno(stdin), _O_BINARY);

    FILE *f = fopen(outfilename, "w+b");
    if (f == NULL)
    {
        printf("unable to open %s\n", outfilename);
        exit(1);
    }

    for (;; )
    {
        r = fread(rbuf, 1, sizeof(rbuf), stdin);
        if (r > 0)
        {
            size_t w;
            for (size_t nleft = r; nleft > 0; )
            {
                w = fwrite(rbuf, 1, nleft, f);
                if (w == 0)
                {
                    printf("error: unable to write %d bytes to %s\n", nleft, outfilename);
                    exit(1);
                }
                nleft -= w;
                fflush(f);
            }
        }
        else
        {
            Sleep(10); // wait for more input, but not in a tight loop
        }
    }

    return 0;
}

答案 4 :(得分:0)

我不知道你在运行什么操作系统,但你通常不能“以二进制方式打开stdin”。你可以试试像

这样的东西
int fd = fdreopen (fileno (stdin), outfname, O_RDONLY | OPEN_O_BINARY);

试图强迫它。然后使用

uint32_t opcode;
read(fd, &opcode, sizeof (opcode));

但我自己没有尝试过。 :)

答案 5 :(得分:0)

对于Windows,此Microsoft _setmode example特别显示了如何将stdin更改为二进制模式:

// crt_setmode.c
// This program uses _setmode to change
// stdin from text mode to binary mode.

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

int main( void )
{
   int result;

   // Set "stdin" to have binary mode:
   result = _setmode( _fileno( stdin ), _O_BINARY );
   if( result == -1 )
      perror( "Cannot set mode" );
   else
      printf( "'stdin' successfully changed to binary mode\n" );
}

答案 6 :(得分:-1)

fread()最适合读取二进制数据。

是的,如果您计划按字节处理它们,则char数组正常。

答案 7 :(得分:-2)

我第一次没错,除了,我需要ntohl ...... C Endian Conversion : bit by bit