0

所以我使用以下代码:

unsigned long replaceByte(unsigned long original,unsigned char newByte,int indexToReplace)
{
    int shift = 8 * indexToReplace;
        unsigned long value = newByte << shift;
        unsigned long mask = 0xff << shift;

        return (~mask & original) | value;
}

我有一个给定的单词 |w| 字节。

  • 字节从 0(最低有效)到 w/8-1(最高有效)编号。

例如:

replaceByte(unsigned long original, unsigned char newByte, int indexToReplace)
correct answer:
replaceByte(0x12345678CDEF3456, 0xAB, 2) --> 0x1234AB78CDEF3456
                       (my code's output is: 0x12345678CDAB3456)
correct answer:
replaceByte(0x12345678CDEF3456, 0xAB, 0) --> 0xAB345678CDEF3456
                       (my code's output is: 0x12345678cdef34AB)

我想我需要检查系统是大端还是小端,因为我的代码更改了完全相反的字节。例如,它改变了 MSB 而不是 LSB。但是......我意识到这并不重要,因为我正在处理比特。

如您所见,此处的代码更改了错误的索引:

(!) Error in index: 0. Output: 0x123456789abcdeff
Answer: 0xff3456789abcdeab

 (!) Error in index: 1. Output: 0x123456789abcffab
Answer: 0x12ff56789abcdeab

(!) Error in index: 2. Output: 0x123456789affdeab
Answer: 0x1234ff789abcdeab

 (!) Error in index: 3. Output: 0xffffffffffbcdeab
Answer: 0x123456ff9abcdeab

 (!) Error in index: 4. Output: 0x123456789abcdeff
 Answer: 0x12345678ffbcdeab

(!) Error in index: 5. Output: 0x123456789abcffab
 Answer: 0x123456789affdeab

 (!) Error in index: 6. Output: 0x123456789affdeab
 Answer: 0x123456789abcffab

好吧,我想过将我的代码更改为带有数组的东西,只是为了获得一个数字-> 作为数组在其上运行-> 更改所需的索引-> 就是这样。但是..我不能正确地写它所以我坚持移动的东西(我也不能正确地写)。这是我的尝试:

    unsigned long replaceByte(unsigned long original, unsigned char newByte, int indexToReplace){
    int size = (sizeof(unsigned long));
char a[size];
for (int i=0; i<size; i++){
if (i=0)
a[0] = original & 0xff;
else
a[i] = original>>(8*i) & 0xff;
}
a[indexToReplace] = newByte;
......// stuck
 }

我不允许使用 long long、uint_fast64_t 或 reinterpret_cast 或任何其他“外部”的东西。

我还认为如果代码在 32 位系统或 64 位系统上运行,我需要以某种方式进行更改,以确定哪个大小是无符号长(4 或 8 字节)。

4

1 回答 1

1

这以 [我的] 热门评论为开头。

value并且mask需要unsigned long

此外,在进行移位时,由于表达式提升规则,这两个值都被截断 [到 32 位]。

在上面,我忘了value有同样的问题。


这是强制正确换档的另一种方法:

unsigned long
replaceByte(unsigned long original,unsigned char newByte,int indexToReplace)
{
    int shift = indexToReplace*8;
    unsigned long value = newByte;
    unsigned long mask = 0xff;

    value <<= shift;
    mask <<= shift;

    return (~mask & original) | value;
}

以上是平时做的。但是,以下方法也可能有效:

unsigned long
replaceByte(unsigned long original,unsigned char newByte,int indexToReplace)
{
    int shift = indexToReplace*8;
    unsigned long value = ((unsigned long) newByte) >> shift;
    unsigned long mask = ((unsigned long) 0xff) >> shift;

    return (~mask & original) | value;
}

更新:

嘿,谢谢。提供的代码为我带来以下输出:0x12345678cdef34AB 而不是 0xAB345678CDEF3456。我很确定它与小端的东西有关,因为取代 MSB 而不是 LSB 并不是巧合。

不是字节序的事情。这是indexToReplace需要如何解释的。

处理器根据有效的字节序模式取数据,所以当我们尝试进行移位时,处理器寄存器中的值总是大字节序[所以,不用担心]

正常/通常是索引从右侧开始。但是,根据 [正确] 数据,问题希望索引从左侧开始。

所以,我们只需要调整索引/移位:

unsigned long
replaceByte(unsigned long original,unsigned char newByte,int indexToReplace)
{
#if 0
    int shift = indexToReplace * 8;
#else
    int shift = ((sizeof(unsigned long) - 1) - indexToReplace) * 8;
#endif
    unsigned long value = newByte;
    unsigned long mask = 0xff;

    value <<= shift;
    mask <<= shift;

    return (~mask & original) | value;
}

更新#2:

它识别“int shift = indexToReplace * 8;” 出于某种原因作为评论,但它仍然有效。

那是因为#if 0是 CPP [预处理器] 语句。它的解释方式类似于#ifdef NEVERWAS我们从不执行 a 的方式#define NEVERWAS,因此包含在下面的代码#else

您可能希望在编译时使用-Eand/or-P选项来查看预处理器阶段的输出

在这种情况下,编译器将看到的唯一内容是:

int shift = ((sizeof(unsigned long) - 1) - indexToReplace) * 8;

但是,如果我尝试将“#if 0”更改为“#if (is_big_endian == 0)”,当我使用“0”作为 indexToReplace 时,我会得到错误的结果。

请尽量不要将其称为与字节序相关的内容。再一次,这不是正在发生的事情。无论处理器字节序模式如何,我发布的代码都有效。

请重新阅读有关正确/正确解释字节索引的部分。这是人们选择对字节进行编号的方式。

再一次,99.44% 的时间,它是从右边定向的(LSB 到 MSB)。从图形上看,大多数人使用:

| MSB |     |     |     |     |     |     | LSB |
|  01 |  23 |  45 |  67 |  89 |  AB |  CD |  EF | DATA
|   7 |   6 |   5 |   4 |   3 |   2 |   1 |   0 | INDEX

但是,对于您的确切问题陈述,它从左侧(MSB 到 LSB)定向:

| MSB |     |     |     |     |     |     | LSB |
|  01 |  23 |  45 |  67 |  89 |  AB |  CD |  EF | DATA
|   0 |   1 |   2 |   3 |   4 |   5 |   6 |   7 | INDEX

这是不寻常的。它也较慢,因为移位的计算更复杂。

它给出: 0x12345678CDEF34FF 而不是 0xFF345678CDEF3456

最终,无论你对 做了什么#if,它都选择了错误的等式。

于 2020-11-20T22:50:51.407 回答