C读二进制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上工作……?

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

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

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

 freopen(NULL, "rb", stdin); 

这将重新打开stdin为相同的输入流,但是在二进制模式下。 在正常模式下,从Windows上的stdin读取将\r\n (Windows换行符)转换为单字符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  # include  # define SET_BINARY_MODE(handle) setmode(handle, O_BINARY) #else # define SET_BINARY_MODE(handle) ((void)0) #endif 

有关SET_BINARY_MODE宏的更多详细信息:“ 通过标准I / O处理二进制文件 ”

关于setmode更多细节: “_ setmode

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

我最近使用read()调用完成了你想做的事情。 除非您的程序已明确关闭stdin,否则对于第一个参数(文件描述符),您可以对stdin使用常量值0。 或者,如果您使用的是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)); 

但我自己没有尝试过。 🙂

我不得不从上面那些人的各种评论中得出答案,所以这里有一个完整的工作样本 – 仅适用于Windows,但您可以将特定于Windows的内容转换为您的平台。

 #include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "windows.h" #include  #include  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; } 

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

是的,如果您计划以字节方式处理它们,则char数组是可以的。

我第一次做对了,除了,我需要ntohl … C Endian转换:一点一滴