C:在程序中使用fwrite()和变量

时间:2011-06-17 20:08:26

标签: c variables fwrite

有没有办法使用fwrite方法读取变量(动态数组)而不是FILE *,或者某种替代方法可以让我这样做?我需要读取包含16位块的二进制文件,但只读取每个块的最后12位。理想情况下,我想要这样的东西:

fwrite(&(x+4),sizeof(x)-4,1,var);

但是目前,我无法直接写入var,只能写入文件。

我知道它可能使用bitmasks / bitops,但这是一种更简单的方式,所以我更愿意在可能的情况下使用它。

4 个答案:

答案 0 :(得分:1)

不,fwrite写一些像文件一样被访问的内容(FILE *)。

也许您想使用sprintf将数据格式化为字符串?

答案 1 :(得分:0)

C是面向字节的,而不是面向位的。

读取两个16位整数,并通过削减前4位将它们组合成24位(3个字节)。

for(;;) {
  uint8_t current;
  uint16_t d[2];
  if(fread(d,sizeof d,2,my_file) != 2) //convert the int if it's in the 
                                        //oposite endian of your host.
     return;
   current = (d[0] & 0xff0) >> 4) ;
   if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
      return;
    current = (d[0] & 0xf) << 4;
    current |= (d[1] & 0xf00) >> 8) ;
    if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
       return;
     current = d[1] & 0xff;
     if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
        return;
 }

Alternativly一次读取一个16位int:

int state = 0;
uint8_t current;
for(;;) {
  uint16_t d;
  if(fread(&d,sizeof d,1,my_file) != 1) //convert the int if it's in the 
                                        //oposite endian of your host.
     return;
   switch(state)
      case 0:
        current = (d & 0xff0) >> 4) ;
        if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
          return;
        current = (d & 0xf) << 4;
        state = 1;
        break;
     case 1;
        current |= (d & 0xf00) >> 8) ;
        if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
          return;
        current = d & 0xff;
        if(fwrite(&current,1,1,my_outfile) != 1) //or store it in an array.
          return;
        state = 0;
        break;
    }
 }

答案 2 :(得分:0)

读取16位。假设CHAR_BIT为8(通常)为2个字节:

size_t chk;
unsigned char data16[2];
chk = fread(data16, 2, 1, file);
if (chk != 1) {
    /* handle error */
}

现在,根据字节顺序问题,只需忽略读取的16位中的右4:

     data16 has, for instance: 01000101 11101011 (data16[0] == 0x45; data16[1] == 0xeb)
     and you want these bits:  ^^^^^.^^ ^..^^^.^
     so ... mask and shift!
/* mask and shift, bit by bit */
data12[0] = 0;
data12[0] |= !!(data16[0] & (1 << 7)) << 3;
data12[0] |= !!(data16[0] & (1 << 6)) << 2;
data12[0] |= !!(data16[0] & (1 << 5)) << 1;
data12[0] |= !!(data16[0] & (1 << 4)) << 0;
data12[1] = 0;
data12[1] |= !!(data16[0] & (1 << 3)) << 7;
data12[1] |= !!(data16[0] & (1 << 1)) << 6;
data12[1] |= !!(data16[0] & (1 << 0)) << 5;
data12[1] |= !!(data16[1] & (1 << 7)) << 4;
data12[1] |= !!(data16[1] & (1 << 4)) << 3;
data12[1] |= !!(data16[1] & (1 << 3)) << 2;
data12[1] |= !!(data16[1] & (1 << 2)) << 1;
data12[1] |= !!(data16[1] & (1 << 0)) << 0;

答案 3 :(得分:0)

编辑添加更好的答案

从注释中看起来你想要压缩一个缓冲区 - 一个16位整数数组,通过剥离4位并将它们打包在一起,对吗?

这段代码可以解决问题:

#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>

typedef unsigned int   UINT32 ;
typedef unsigned short UINT16 ;

void compress( UINT16 *buf , int *cnt )
{
  UINT16 *src   = buf        ; // where we're copying from
  UINT16 *tgt   = buf        ; // where we're copying to
  UINT16 *limit = buf + *cnt ; // endpoint address
  UINT16  bits  = 0x0000     ;
  int     state = 0          ;

  while ( src < limit )
  {
    switch ( state )
    {
    case 0 :
      bits    = (*src++ & 0x0FFF ) <<  4 ;
      state   = 1 ;
      break ;
    case 1 :
      bits   |= (*src   & 0x0F00 ) >>  8 ;
      *tgt++  = bits ;
      bits    = (*src++ & 0x00FF ) <<  8 ;
      state   = 2 ;
      break ;
    case 2 :
      bits   |= (*src   & 0x0FF0 ) >>  4 ;
      *tgt++  = bits ;
      bits    = (*src++ & 0x000F ) << 12 ;
      state   = 3 ;
      break ;
    case 3 :
      bits   |= (*src++ & 0x0FFF ) ;
      *tgt++  = bits ;
      bits    = 0x000 ;
      state   = 0 ;
      break ;
    }
  }

  if ( state != 0 )
  {
    *tgt++ = bits ;
  }

  // hand back the new size ;
  *cnt = (tgt - buf ) ;

  while ( tgt < limit )
  {
    *tgt++ = 0x0000 ;
  }

  return ;
}

int main( int argc, char* argv[])
{
  UINT16 buf[] = { 0xF123 , 0xE456 , 0xD789 , 0xCABC , 0xBDEF , } ;
  int    bufl  = sizeof(buf) / sizeof(*buf) ;

  compress( buf , &bufl ) ;

  // buf now looks like { 0x1234 , 0x5678 , 0x9ABC , 0xDEF0 , 0x0000 }

  return 0 ;
}

原始回答

如果你真的想要从一个文件中读取 16位结构并且有12个有趣的位和4个未使用的(或不是非常有趣的)位,并且你想要避免位杂乱,那么你可以使用位字段

请注意,在这些内容的工作原理标准下,实现获得了很多的余地,因此它至少不可移植:您可能需要调整结构对齐和可能的字段顺序,具体取决于在底层CPU上。您将注意到我使用#pragma pack(2)将结构强制转换为16位大小 - 适用于Visual Studio 2010 C ++。 YMMV等等。

[你确定你不想掩盖你不想要的东西?]

无论如何,一旦你处理了所有这些,类似下面的代码应该适合你:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#pragma pack(2) // necessary to get correct alignment
typedef struct
{
    unsigned short unused :  4 ;
    unsigned short value  : 12 ;
} CHUNK ;
#define BUFFER_CHUNKS ((size_t)8192)

void process( FILE*input )
{
  CHUNK *buf    = (CHUNK*) calloc( BUFFER_CHUNKS , sizeof(CHUNK) ) ;
  size_t bufl   = BUFFER_CHUNKS * sizeof(CHUNK) ;
  int    chunks = 0 ;

  while ( 0 > (chunks=(int)fread( (void*)buf , sizeof(CHUNK) , BUFFER_CHUNKS , input ) ) )
  {
    for ( int i = 0 ; i < chunks ; ++i )
    {
      int value = buf[i].value ;
      printf( "%d: %d\n" , i , value ) ;
    }
  }

  return ;
}

祝你好运!