在c中从8位压缩到7位

compressing from 8 bit to 7 in c

我是这个网站的新手,所以我希望这是正确的提问地点。 我的任务是将包含 8 位字符的文本文件压缩为 7 位字符以保存 space 并能够将其还原并解码回 8。因为最后一位始终为 0,这是一个无损压缩(假设我们在 127 之后不使用任何 ascii 字符) 我意识到有一个相对相似的 post (Compress 8 chars in 7 bytes) 但是我采取的方法完全不同,我想知道为什么它不起作用以及如何改进这个想法。

我的压缩思路如下:压缩位[i]应该是i+offset位右移i+1%8,每次i除以8时offset增加1

对于解码部分:新的位[i]应该等于压缩后的位[i]右移i次&~1

如果可以的话,我会上传我的逻辑草图,但代码就足够了。

两者的输出是我写入和读入 f 的文件在此代码之前完成并经过测试

压缩代码:

int offset = 1,size = strlen(f); //f is a char* buffer that I read the whole file to
for(int i = 0; i < size; i++)
{
    if(offset%8 == 0)
        offset++;
    shift_right(f,size,(i+1)%8);
    fputc(f[i+offset],output);
}

解码代码:

unsigned char temp;
for (int i = 0; i < actualLen; ++i) //actualLen being the length of the uncompressed file in chars(bytes)
{
    temp = f[i]&(~1);
    fputc(temp,output);
    shift_right(f,actualLen,1); //f is a char* buffer that I read the whole file to
}

右移函数:

   void shift_right(unsigned char *ar, int size, int shift)
{//credit to another post here for this function :)
    int carry = 0;                              // Clear the initial carry bit.
    while (shift--) {                           // For each bit to shift ...
        for (int i = size - 1; i >= 0; --i) {   // For each element of the array from high to low ...
            int next = (ar[i] & 1) ? 0x80 : 0;  // ... if the low bit is set, set the carry bit.
            ar[i] = carry | (ar[i] >> 1);       // Shift the element one bit left and addthe old carry.
            carry = next;                       // Remember the old carry for next time.
        }
    }
}

提前感谢您的帮助:)

压缩意味着写入的输出字节数少于输入字节数。在最简单的层面上,您的程序无法运行,因为它不适合这样做。您遍历文件的所有字节:

for(int i = 0; i < size; i++)
{

尽管您执行了计算,但对于每个输入字节,您...

    fputc(f[i+offset],output);
}

这可以实现某种密码,但它总是会为每个输入字节得到一个字节的输出(因此,没有压缩)。

我认为这里存在一个基本的概念错误,因为这个想法...

the compressed bit[i] should be the i+offset bit shifted right by i+1 % 8 when the offset increases by one each time i divides by 8

... 似乎将在 整个输入 上运行的算法描述为位数组,但您已尝试在每个字节上单独实现它。

还有一个可能的次要错误,你说的是右移,但从 bit-array 的角度来看,你似乎实际上想要 移,因为我们通常认为二进制数被写成 most-significant 位到最少,并且术语“左移”和“右移”是根据这种表示定义的。左移将位移向 more-significant 位置(== 在 bit-array 视图中移向数组的前面),而 right-shifting 将它们移向相反的方向。如果您根本不提及移动,您的描述实际上会更符合我认为您的想法:

”压缩位[i]应该是输入位[i+offset],其中offset 从 1 开始,每除以 8 就加 1 i > 0."

请注意,除了可能的最后一个字节外,每个输出字节都包含来自两个输入字节的位,并且每个 7 个输出字节块都包含 8 个输入字节的所有位。这是我的实施建议的基础:

  • 维护一个 8 字节的输入缓冲区和一个 7 字节的输出缓冲区。
  • 一次读取输入 8 个字节,并根据您的方案将它们打包到输出缓冲区的 7 个字节中。
  • 将每个完整的 7 字节压缩组作为一个单元输出
  • 不要忘记对文件的最后一个块实施适当的处理,它通常不会包含完整的 8 个字节。