C: использовать fwrite () с переменными в программе - PullRequest
0 голосов
/ 18 июня 2011

Есть ли способ использовать метод fwrite для чтения в переменную (динамический массив) вместо FILE *, или какой-нибудь альтернативный метод, который позволяет мне это делать?Мне нужно прочитать двоичный файл, содержащий 16-битные чанки, но читать только последние 12 бит каждого чанка.В идеале я хочу что-то вроде:

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

Но в настоящее время я не могу записать в var напрямую, только файл.

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

Ответы [ 4 ]

1 голос
/ 18 июня 2011

Нет, fwrite записывает что-то, что может быть доступно как файл (FILE *).

Возможно, вы хотите использовать sprintf для форматирования данных в строку?

0 голосов
/ 18 июня 2011

ИЗМЕНЕНО ДЛЯ ДОБАВЛЕНИЯ ЛУЧШЕГО ОТВЕТА

Судя по комментариям, вы хотите сжать буфер - массив 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 неиспользуемых (или не очень интересных) бита, и вы хотите избежать сдвоения битов, вы можете используйте битовые поля .

Обратите внимание, что реализации в соответствии со стандартом получают лот свободы в соответствии со стандартом, поэтому он не является переносимым по меньшей мере: вам, вероятно, потребуется настроить выравнивание структуры и, возможно, порядок полей, в зависимости от базовый процессор. Вы заметите, что я использовал #pragma pack(2) для приведения структуры в 16-битный размер & mdash; это работает в 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 ;
}

Удачи!

0 голосов
/ 18 июня 2011

Читать 16 бит.Предполагая, что CHAR_BIT равен 8 (обычно), что составляет 2 байта:

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

Теперь, в зависимости от проблем с порядком байтов, просто проигнорируйте правильные 4 из этих 16 битов:

     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;
0 голосов
/ 18 июня 2011

C ориентировано на байты, а не на биты.

считывает два 16-битных целых и объединяет их в 24-битные (3 байта), сбрасывая верхние 4 бита.

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;
 }

Альтернативно читайте их по одному 16-битному целому разу:

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;
    }
 }
...