这段代码是怎么回事?

What is going on in this code?

有人可以为我解释一下代码吗?

为什么是 32 位 UINT

为什么 0xff

这里的 4 个右移是做什么的?

int writeUINT32little(FILE *f, UINT32 i)
{    
    int rc;    
    rc = fputc((i & 0xff), f);    
    if (rc == EOF)       return rc;    
    rc = fputc(((i >> 8) & 0xff), f);    
    if (rc == EOF)       return rc;    
    rc = fputc(((i >> 16) & 0xff), f);    
    if (rc == EOF)       return rc;    
    return fputc(((i >> 24) & 0xff), f);
}

这需要一个 32 位无符号整数并将其逐字节输出到文件,最低有效字节在前(即小端)。

0xff是十六进制的写法,十进制写255,二进制写11111111& 是按位 and 函数。放在一起,(i & 0xff) 屏蔽掉整数的最低有效字节。

然后移位将整个内容移位超过 8 位,并重复该过程以打印下一个字节。

这个函数据推测所做的是将一个 32 位无符号整数写入小端格式的文件流。

它真正做的是,它不是做一个简单的小任务并把它做对,而是试图同时做两件事,但都做错了。

在深入探讨为什么这是错误的之前,我将快速回答问题本身:

  • 为什么UINT32?不知道。它是非标准的,最好用 uint32_t.
  • 代替
  • 为什么0xff?用作将低 8 位保留在较大变量(32 位)中的掩码
  • 4个右移在这里做什么?移位用于将原始 UINT 中的每个字节以正确的 "little-endian" 顺序移至​​最右边的位。


现在,将其排除在外...

为什么这是错误的?
char 保证是 at least 8 bits wide,但 可以 更大。这意味着 fputc 每次调用可能会写入 8 位,但它可能会写入更多。这意味着在 char 为(例如)16 位的特定体系结构上,该函数每次调用将写入 64 位并且它根本不是小端。此外,该函数非常仔细地检查错误,但不会向调用者公开相关的失败信息(写入了多少字节?)。

什么是更好的设计?
首先,一如既往,做一件小事,并把它做好:

uint32_t toLittleEndian(uint32_t v)
{
    uint32_t result = v >> 24;
    result |= v << 24;
    result |= (v >> 8) & 0xf0;
    result |= (v << 8) & 0xf00;
    return result;
}

注意:此实现故意冗长。有一个使用位旋转操作的优化机会,但 C 对此没有原生支持,需要汇编代码

此函数将大端32位值转换为其等效的小端表示(实际上它在两者之间交替并且可以命名为switchEndian) .

接下来,我们需要将值写入文件:

int write(uint32_t v, FILE *f)
{
    return fwrite(&v, sizeof(v), 1, f);
}

这将写入正好 32 位宽整数,return 实际写入的字节数。此外,它是可重复使用的。

接下来,如果需要,我们可以创建一个方便的复合函数:

int writeLittleEndian(uint32_t v, FILE *f)
{
    return write(toLittleEndian(v), f);
}