c - 位 vector 运算和字节顺序

标签 c bit-manipulation endianness bitvector

我在我的软件中进行了大量的位 vector 运算。例如:假设我需要存储有关候选“n”的 bool 信息,我执行以下操作:

uint64_t *information_vector;
uint32_t pos = n / 64;
uint32_t bit_pos = n % 64;

information_vector[pos] |= (1 << bit_pos);

我在阅读该信息时遵循类似的程序:

uint32_t pos = n / 64;
uint32_t bit_pos = n % 64;
if (information_vector[pos] & (1 << bit_pos)) {
       // do something
}

同时,我还将 information_vector 写入磁盘并再次读回。现在,我正在尝试解决一个让我做噩梦的错误,我突然意识到 Endianess 可能是这里的罪魁祸首,但我无法解释。有什么办法可以检查吗?这种位 vector 操作通常是字节序安全的并且跨架构吗?

我还发现,在代码中的某个位置,我在另一个位 vector 中为同一候选者设置了一些其他信息:

uint8_t byte_position = n / 8;
uint8_t bit_position = n % 8;
another_information_vector[byte_position] |= (1 << bit_position);

我通常通过对这些位 vector 进行“与”运算来找到常见的属性集。

最佳答案

一般来说,如果您始终使用相同的类型访问位 vector (在您的情况下是 uint64_t ),并且您访问数据的所有系统的字节序是相同的,那么字节序将不会成为一个问题。

不过,让自己放心的最简单方法是将对象的地址转换为 char*和取消引用,这将使您按照它们在内存中的排列顺序一次看到一个字节。

更新:我刚刚观察到你的第三个代码块似乎计算 byte_position通过这样做n % 8

如果您有时会写出 uint64_t 的数组,有时将其视为 uint8_t 的数组,那么如果您的系统是小尾数法,您的结果可能会出乎意料。

避免此问题的最佳方法是保持类型一致。

To make this problem more concrete, consider the following example:

#include <stdio.h>
#include <stdint.h>

int main(){
    uint64_t myVector = 1 << 2; // set second bit of LSB
    uint8_t * ptr = (uint8_t *) &myVector;
    int i;
    for (i = 0; i < 8; i++)
       printf("%x\n", ptr[i]);
}

在我的小端上 x86系统,这将打印 4接下来是 7 0的,因为最高有效字节存储在 uint64_t 中最高地址的地址处。 。如果您习惯于思考从最重要到最不重要、从左到右排列的位,这可能会与您的直觉相悖。

关于c - 位 vector 运算和字节顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23253779/

相关文章:

perl - 使用 perl 查找系统是小端还是大端

c - 写入关闭的本地 TCP 套接字不会失败

c - 获取簇大小

c - 双向链表中的注入(inject)函数在调用 pop() 后任意指向头元素

c - Mac OS 等同于 Windows Fibers API?

c++ - 检查 uint8_t[8] 是否包含任何非 0 并使用一次内存负载访问非零插槽

c# - BinaryWriter Endian 问题

c# - 位标志 - 我错过了什么?

c - 快速计算 64 位整数的 log2

mips - 大端和小端