这段代码发生了什么?

时间:2016-02-26 06:58:24

标签: c bitwise-operators endianness

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

为什么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);
}

2 个答案:

答案 0 :(得分:8)

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

0xff是以十进制编写255或以二进制编写11111111的十六进制方式。 &是按位and函数。放在一起,(i & 0xff)掩盖整数的最低有效字节。

然后,移位将整个事物移位到8位,并重复该过程以打印下一个字节。

答案 1 :(得分:1)

这个函数应该做的是将一个32位无符号整数写入little-endian的文件流中。

它真正做的是,它不是做一个简单的小任务并且做得对,而是尝试一起做两件事并且两者都错了。

在我说明为什么这是错的之前,我会快速回答这个问题:

  • 为什么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没有本机支持,需要汇编代码

此函数将big-endian 32位值转换为其等效的little-endian表示(实际上它在两者之间交替,可以命名为switchEndian)。

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

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

这将写入完全 32位宽的整数,并返回实际写入的字节数。此外,它可以重复使用。

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

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