Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中一次向二进制文件写入3位_C_Binaryfiles_Bit Shift - Fatal编程技术网

在C语言中一次向二进制文件写入3位

在C语言中一次向二进制文件写入3位,c,binaryfiles,bit-shift,C,Binaryfiles,Bit Shift,您好,我有一个链接列表中存储的图像中描述的位置列表。每个节点都有一个大小为2的无符号字符(代码中的chessPos)——第一个位置表示一行,第二个位置表示一列。例如,第一个节点:row='C',col='5',依此类推。列表通过函数传递,我不需要构建它 我需要将数据写入一个二进制文件,当每行或每列写入3位时。因此,“C”将被写为010,紧接着“5”将被写为100(写的3位代表行/列-1,这就是为什么“5”用100表示,100是二进制的4) 困难在于每个字节是8位,每次我向文件写入一个字节时,它包

您好,我有一个链接列表中存储的图像中描述的位置列表。每个节点都有一个大小为2的无符号字符(代码中的chessPos)——第一个位置表示一行,第二个位置表示一列。例如,第一个节点:row='C',col='5',依此类推。列表通过函数传递,我不需要构建它

我需要将数据写入一个二进制文件,当每行或每列写入3位时。因此,“C”将被写为010,紧接着“5”将被写为100(写的3位代表行/列-1,这就是为什么“5”用100表示,100是二进制的4)

困难在于每个字节是8位,每次我向文件写入一个字节时,它包含6位,代表一行和一列,下一个字节包含2位

我怎样才能让它工作

谢谢

这是我目前的代码:

      typedef char chessPos[2];
    
    
    typedef struct _chessPosArray {
        unsigned int size;
        chessPos* positions;
    }chessPosArray;
    
    typedef struct _chessPosCell {
        chessPos position;
        struct _chessPosCell* next;
    }chessPosCell;
    
    typedef struct _chessPosList {
        chessPosCell* head;
        chessPosCell* tail;
    }chessPosList;

 

    void function_name(char* file_name, chessPosList* pos_list)
{

    FILE* file;
    short list_len;
    int i = 0;
    unsigned char row, col, byte_to_file, next_byte;
    chessPosCell* curr = pos_list->head;


    file = fopen(file_name, "wb"); /* open binary file to writing */
    checkFileOpening(file);

    
    while (curr != NULL)
    {
        row = curr->position[0] - 'A' - 17; /* 'A' ---> '1' ---> '0' */
        col = curr->position[1] - 1; /* '4' ---> '3' */

        if (remain < 6)
        { 
            curr = curr->next;
            remain += 8;                
        }

        if (i > 1)
        {
            i = 0;
        }

        if (curr->next != NULL)
        {
            next_byte = curr->next->position[i] >> (remain - 7);
            byte_to_file = ((row << (remain - 3)) | (col << (remain - 6))) | (next_byte);
            i++;
        }
        else
        {
            byte_to_file = ((row << (remain - 3)) | (col << (remain - 6)));
        }

        fwrite(&byte_to_file, sizeof(unsigned char), 1, file);

        remain -= 6;                    
             
    }
typedef char chessPos[2];
类型定义结构\u chessPosArray{
无符号整数大小;
棋子*位置;
}棋子阵列;
类型定义结构\u棋盘格{
棋子位置;
结构_chessPosCell*下一步;
}棋盘格;
类型定义结构\u棋盘列表{
棋盘格*头;
棋盘格*尾巴;
}棋盘清单;
无效函数名(字符*文件名,棋子列表*位置列表)
{
文件*文件;
短名单;
int i=0;
无符号字符行、列、字节到文件、下一个字节;
chessPosCell*curr=pos\u list->head;
file=fopen(文件名,“wb”);/*打开二进制文件进行写入*/
检查文件打开(文件);
while(curr!=NULL)
{
行=当前->位置[0]-'A'-17;/*'A'-->'1'-->'0'*/
col=curr->position[1]-1;/*“4”-->“3”*/
如果(保持<6)
{ 
当前=当前->下一步;
剩余+=8;
}
如果(i>1)
{
i=0;
}
如果(当前->下一步!=NULL)
{
下一个字节=当前->下一个->位置[i]>>(保持-7);
字节到文件=((行)
我怎样才能让它工作

首先,从一个好的抽象开始。无论如何,它实际上非常简单:

  • 让我们看一个16位/2字节的缓冲区和缓冲区中的一个位位置
    • 如果继续使用缓冲区(
      uint16\u t
      ),而不是两个单独的字节(
      无符号字符字节到文件,下一个字节到文件),则会更容易。下一个字节到文件的
      位只需自身移位,并且可以用掩码提取
      字节到文件
  • 我在想象中看到左边的MSB和右边的LSB
  • 对于每个新的6位,将其推到尚未设置的最左侧位置
    • 所以16-6的移位减去位置
  • 如果我们填充超过8位
    • 取一个字节并输出它
    • 并将缓冲器的8位向左移位
下面是一个示例程序,用于打印
Hello world\n

#include <stdint.h>
#include <stdio.h>

struct bitwritter {
    FILE *out;
    // our buffer for bits
    uint16_t buf;
    // the count of set bits within buffer counting from MSB
    unsigned char pos;
};

struct bitwritter bitwritter_init(FILE *out) {
   return (struct bitwritter){ .out = out };
}

int bitwritter_write_6bits(struct bitwritter *t, unsigned char bits6) {
   // we always write starting from MSB
   unsigned char toshift = 16 - 6 - t->pos;
   // just a mask with 6 bits
   bits6 &= 0x3f;
   t->buf |= bits6 << toshift;
   t->pos += 6;
   // do we have whole byte?
   if (t->pos >= 8) {
      // extract the byte - note it's in MSB
      unsigned char towrite = t->buf >> 8;
      // shift out buffer
      t->buf <<= 8;
      t->pos -= 8;
      // write output
      if (fwrite(&towrite, sizeof(towrite), 1, t->out) != 1) {
             return -1;
      }
      return 1;
   }
   return 0;
}

int main() {
    struct bitwritter bw = bitwritter_init(stdout);
    // echo 'Hello world' | xxd -c1 -p | while read l; do python -c "print(\"{0:08b}\".format(0x$l))"; done | paste -sd '' | sed -E 's/.{6}/0b&,\n/g'
    unsigned char data[] = {
        0b010010,
        0b000110,
        0b010101,
        0b101100,
        0b011011,
        0b000110,
        0b111100,
        0b100000,
        0b011101,
        0b110110,
        0b111101,
        0b110010,
        0b011011,
        0b000110,
        0b010000,
        0b001010,
    };
    for (size_t i = 0; i < sizeof(data); ++i) {
        bitwritter_write_6bits(&bw, data[i]);
    }
}
 
#包括
#包括
结构位写器{
归档;
//我们的比特缓冲区
uint16_t buf;
//从MSB开始的缓冲区计数中的设置位计数
无符号字符位置;
};
结构BitWriter BitWriter_init(文件*out){
返回(结构位写器){.out=out};
}
int BitWriter_write_6位(结构BitWriter*t,无符号字符位6){
//我们总是从MSB开始写
无符号字符toshift=16-6-t->pos;
//只有一个6位的面具
位6&=0x3f;
t->buf |=位6位置+=6;
//我们有完整的字节吗?
如果(t->pos>=8){
//提取字节-注意它在MSB中
无符号字符towrite=t->buf>>8;
//移位缓冲器
t->buf out)!=1){
返回-1;
}
返回1;
}
返回0;
}
int main(){
结构BitWriter bw=BitWriter_init(stdout);
//回音'Hello world'| xxd-c1-p |同时读取l;执行python-c“打印(\“{0:08b}\”.format(0x$l));“完成”|粘贴-sd'| sed-E的s/{6}/0b&,\n/g
无符号字符数据[]={
0b010010,
0b000110,
0b010101,
0b101100,
0b011011,
0b000110,
0b111100,
10万美元,
0b011101,
0b110110,
0b111101,
0b110010,
0b011011,
0b000110,
0b010000,
0b001010,
};
对于(大小i=0;i
我怎样才能让它工作

因为每个位置都需要一列和一行,你可以把一个位置想象成一个6位的值,其中最低的3位是行,最高的3位是列。如果你这样想的话,那么问题就简单了一点,因为你实际上只是在谈论base-64编码/解码,并且有lo如果您真的想将数据打包到尽可能小的空间中,那么可以使用多种开源实现


这样的话,我会鼓励你考虑你的问题是否真的需要最小化存储空间。你可以将这些位置存储为字符,或者使用4位行,4位为列,继续把位置当作6位值,而忽略两个额外的位。除非你存储了大量的这些位置,否则每个位置节省两位的好处可能无关紧要。

当前的问题到底是什么?您需要在字节数组(数组或分配的
无符号字符块
)中缓冲所有输出完成后,将其逐字节写入文件。无法将少于一个字节写入文件。换句话说,在将每个字节写入文件之前,您需要对每个字节进行所有位打包。如果一次确实需要三位,则必须将它们封送到一组字节中。您至少需要三个字节(24位)即使是位和字节。我怀疑文件大小是否真的会成为一个很大的问题。我只会把每个位置都写进去