【问题标题】:Writing a stream of 9 bit values as bytes to a file in C将 9 位值的流作为字节写入 C 中的文件
【发布时间】:2017-11-27 07:39:52
【问题描述】:

我有一个整数值从 0 到 511(最大 9 位)的数组。我正在尝试将其写入带有fwrite 的文件。

以数组为例:

[257, 258, 259]
Which is 100000001, 100000010, 100000011

I am trying to write
100000001100000010100000011 + extra padding of 0s to the file 

但由于 fwrite 一次限制写入 1 个字节,我不知道该怎么做。我是按位运算的新手,不知道如何分离各个字节。

【问题讨论】:

  • Writing integer values to a file in binary using C 密切相关——通过相同的 OP 以及大约 9 位值。
  • 除非您使用一些极不寻常的硬件,否则没有可用的 9 位数据类型。您必须将每个“9 位”值存储在内存和磁盘中的 16 位数据中。我想,理论上你可以在一个 32 位单元中存储 3 x 9 位值。目前,尚不清楚您在追求什么或为什么。如果您正在使用 36 位硬件,请这样说;规则突然改变。曾经有这样的机器;我不认为还有很多人还在运行,但你可能会教育我。
  • @JonathanLeffler 前一个 Q 更笼统,在这个 OP 中特别要求一种方法/算法以最佳方式将 n x 9 位写入 (n x 9)/8+1 字节。如果发布了一个解决方案,我们就可以把它塞进之前的 Q 中。
  • 如果值的范围是 257-512,只需从该值中减去 257 并保存 8 位数量 (0..255)。这将为您省去无尽的头痛。在阅读时,再次添加 257。您将拥有 16 位量,将其映射到一系列 8 位值,并且您将读取一个 8 位值数组并将它们扩展回 16 位量。
  • 玩得开心。我认为即使是虐待狂的老师也不会试图让你使用 9 位数据存储。在计算大小的 2 次方世界中,它根本无法正常工作。

标签: c io bit-manipulation bitwise-operators fwrite


【解决方案1】:

您需要一个位缓冲区。

由于您当时正在写入 8 位,因此您必须 具有至少可以保存至少 9+7 位的数据类型。 uint16_t 可以, 但我建议使用至少与您的原生 int 一样大的尺寸。确保使用无符号类型以避免转移问题。

uint32_t bitBuffer = 0;  // Our temporary bit storage
uint32_t count = 0;      // Number of bits in buffer

假设我们有单个数据:

uint32_t data9b = 257;  // 1 0000 0001

向缓冲区添加位很简单;只需在缓冲区末尾移动位, 并与 OR 结合。

bitBuffer |= (data9b << count); // At first iteration, shift does nothing
count += 9;                     // Update counter

添加 9 位后,我们可以将 8 位刷新到文件中。

while(count >= 8) {
    writeToFile(bitBuffer & 0xFF);  // Mask out lowest bits with AND
    bitBuffer >>= 8;                // Remove written bits
    count -= 8;                     // Fix counter
}

每个周期后,缓冲区中剩余 0 - 7 位。在所有数据的末尾,如果你以非8位的倍数结束,只需将bitBuffer的剩余内容写入文件。

if(count > 0)
    writeToFile(bitBuffer);

【讨论】:

    【解决方案2】:

    好的,使用位移位、oring 也是如此(也可以使用 *、'+'、%/),但移位更合适/更易读,imo。

    // Your data, n is the number of 9-bits values
    uint16_t dat[] = { 257, 258, 259 };
    int i,n = sizeof(dat)/sizeof(*dat);
    
    // out file
    FILE *fp = fopen("f8.bin","w");
    
    uint16_t one = 0;
    int shift = 0;
    uint8_t b;
    
    // main loop
    for(i=0 ; i<n ; i++) {
        b = (dat[i] << shift) | one; // one is remainder from previous value
        one = dat[i]>>(8-shift);     // Move the remaining MSb to the right
        shift = (shift+9) % 8;       // next shift
        fwrite(&b, 1, 1, fp);        // write our b byte
    }
    // remainder, always have a remainder
    fwrite(&one, 1, 1, fp);
    fclose(fp);
    

    玩得开心:-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多