gpt4 book ai didi

c - 我如何编写像 getc() 这样的函数来一次读取一位?

转载 作者:行者123 更新时间:2023-12-01 22:56:54 27 4
gpt4 key购买 nike

我有一个函数读取 unsigned long long 中的每一位并将值存储在数组中,现在我想将此函数转换为返回数字中的下一位并将数据处理留给调用者的函数.

理想情况下,它的工作方式与 getc() 类似,我可以在其中执行以下操作:

int n;
while((n = getbit()) != NULL)
...

我知道静态索引变量是一个选项,但这不是很优雅。有没有更实用的方法来做到这一点?

最佳答案

很像 FILE 结构包裹了输入的各种状态,例如缓冲、错误状态,您可以用一个简单的包裹提取位所需的状态结构:

// Struct used to manage reading bits from a file
struct bitstream
{
FILE *fp;
unsigned char ch; // current char
unsigned char mask; // next bit mask
unsigned char mask0; // first bit mask
};

这会维护正在读取的 FILE,跟踪从该文件读取的最后一个字符,并管理一次将选择一位的位掩码。因为不同的应用程序可能需要特定的 bit order (LSB->MSB 或 MSB->LSB),为此使用了一个额外的成员 mask0。您稍后会看到它是如何使用的。

首先,您需要一个函数来设置此结构,准备好执行操作。让我们有两个函数,它们明确选择所需的位顺序:

// Initialize a bitstream where bit ordering is LSB -> MSB
void bitstream_init_lsb(struct bitstream* bs, FILE *fp)
{
struct bitstream bs_init = { fp };
bs_init.mask0 = 1u;
*bs = bs_init;
}

// Initialize a bitstream where bit ordering is MSB -> LSB
void bitstream_init_msb(struct bitstream* bs, FILE *fp)
{
struct bitstream bs_init = { fp };
bs_init.mask0 = 1u << (CHAR_BIT - 1);
*bs = bs_init;
}

注意这两个函数中mask0的区别。对于 LSB 优先级,mask0 是最低位。对于 MSB 优先级,mask0 是最高位。在这两种情况下,chmask 都是零初始化的。我们可以依靠 mask 的零值来指示已从 ch 中读取所有位,并且我们必须从文件中读取下一个字节。

这将起作用的方式是,每次您阅读一点时,您都​​会在适当的方向(向左或向右,取决于选择的顺序)移动掩码。在任何一种情况下,当位被移位超出其存储能力时,掩码将再次变为零。然后您知道是时候读取下一个字节了。

请注意,上述逻辑明确依赖于 maskunsigned char 类型。这很重要。

// Get next bit (0 or 1) from bitstream, or EOF
int bitstream_get(struct bitstream *bs)
{
// Get next character when next bit is zero
if (bs->mask == 0) {
int ch = fgetc(bs->fp);
if (ch == EOF) {
return EOF;
}
bs->ch = (unsigned char) ch;
bs->mask = bs->mask0;
}

// Get next bit
int result = (bs->ch & bs->mask) ? 1 : 0;
if (bs->mask0 == 1u) {
bs->mask <<= 1;
} else {
bs->mask >>= 1;
}
return result;
}

感谢chux - Reinstate Monica对于他们的建议improvements到我原来的答案。以上是一个修订版,合并了这些更改并明确实现了位排序。

要使用它,您只需使用有效的 FILE* 进行初始化,然后像使用 fgetc 一样执行读取循环:

int bit;
struct bitstream bs;

bitstream_init_msb(&bs, stdin);

while (EOF != (bit = bitstream_get(&bs)))
{
// ...
}

这是一个现场演示:https://godbolt.org/z/KdEMoTavh

关于c - 我如何编写像 getc() 这样的函数来一次读取一位?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72877694/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com