C未正确计算位运算

06odsfpq  于 2023-02-21  发布在  其他
关注(0)|答案(1)|浏览(96)

我有一个16位(无符号短)块的列表,我从程序的另一个部分收到,我想写入一个二进制文件。我试图将这些拆分成8位字符,所以我设计了这个方法:

int blocks = 1;
unsigned short stuffToWrite[blocks];
stuffToWrite[0] = 0b0100101011110111;

int charsPerBlock = sizeof(unsigned short) / sizeof(char);

char charsToWrite[blocks * charsPerBlock];

for (int i = 0; i < blocks; i++) {
    for (int j = 0; j < charsPerBlock; j++) {
        charsToWrite[i*charsPerBlock+j] = (stuffToWrite[i] & ((((int) pow(2, sizeof(char)*8)-1) << ((charsPerBlock-1)*sizeof(char)*8)) >> (j*sizeof(char)*8))) >> ((charsPerBlock-j-1)*sizeof(char)*8);
        // Testing line //
        printf("%u = (%u & %u) >> %lu\n", charsToWrite[i*charsPerBlock+j], stuffToWrite[i], (((int) pow(2, sizeof(char)*8)-1) << ((charsPerBlock-1)*sizeof(char)*8)) >> j*sizeof(char)*8, (charsPerBlock-j-1)*sizeof(char)*8);
}

这看起来很复杂,但实际上并不复杂。我只是创建了一个8位掩码((int) pow(2, sizeof(char)*8)-1)),将其移到第一位(<< ((charsPerBlock-1)*sizeof(char)*8))),然后将其移回正确的位置(>> (j*sizeof(char)*8))))。然后将其与原始块一起移到AND,并将其移回最低位,成为一个字符(>> ((charsPerBlock-j-1)*sizeof(char)*8))。
这对于第一个块来说很好,得到了7401001010。但是,第二个块给了我一个非常大的错误数字。我不确定这里出了什么问题,因为我很确定我的方法工作得很好,所以我写了一个测试行来分解产生以下结果的步骤:

74 = (19191 & 65280) >> 8
4294967287 = (19191 & 255) >> 0

这显然是错误的。
我将感谢任何帮助识别错误和如何修复它(也如果有更好的方法来做到这一点)。

v9tzhpje

v9tzhpje1#

这看起来很复杂,其实不然。
如果你只是想把数据序列化成字节,那么你所需要的就是:

int blocks = 1;
uint16_t stuffToWrite[blocks] = { 0b0100101011110111 };
char charsToWrite[blocks * sizeof(uint16_t)] =
{
  (stuffToWrite[0] >> 8) & 0xFFu,
  (stuffToWrite[0]     ) & 0xFFu,
};

不管传入数据的字节序如何,这种方法都有效,但它假定输出数据的最高有效字节在前。
类似地,对于32位数字,您可以使用>> 24>> 16>> 8>> 0
还请注意,当执行按位算术时,切勿使用以下类型:有符号类型、char、浮点。

相关问题