简体   繁体   English

在 C/C++ 中获取和设置字节中的位

[英]Getting and setting bits in a byte in C/C++

I've created a function that enables you to get a range of bits in a byte, counting bit 0 for the least significant bit (LSb) on the right and 7 for the most significant bit (MSb) on the left for code in C or C++.我创建了一个函数,使您能够在一个字节中获取一系列位,将右侧的最低有效位 (LSb) 的位 0 和左侧的最高有效位 (MSb) 的位 7 计数为 C 中的代码或 C++。 However, it's not so straightforward to set bits.但是,设置位并不是那么简单。 This can be generalized for short, int, long etc., but for now I'm sticking with bytes.这可以概括为 short、int、long 等,但现在我坚持使用字节。

Given the following:鉴于以下情况:

#include <stdio.h>
#typedef unsigned char BYTE;

BYTE getByteBits(BYTE n, BYTE b) {
    return (n < 8) ? b & ((0x01 << (n + 1)) - 1) : 0;
}

where the bits we want to extract are between bits 0 and n, and b is the full byte.其中我们要提取的位在位 0 和 n 之间,b 是完整字​​节。 If n is 0 only 0 or 1 is returned for this LSb, if n is 1, values between 0 and 3 can be returned, etc., up to n is 7 for the full byte.如果 n 为 0,则此 LSb 仅返回 0 或 1,如果 n 为 1,则可以返回 0 到 3 之间的值,依此类推,对于整个字节,最多 n 为 7。 Of course in the latter case the code is redundant.当然,在后一种情况下,代码是多余的。

This can be called from main() by using something like:这可以通过使用类似的东西从 main() 调用:

BYTE num = getByteBits(4, myByte);

which will return the numerical value from the 4 lowest bits.它将返回 4 个最低位的数值。 However, I've discovered that this can be generalized to:但是,我发现这可以概括为:

BYTE num = getByteBits(n - m, myByte >> m);

which will extract the value returned by the bits from m to n, such that 0 <= m <= n <= 7. This is done by shifting myByte by m bits to the right, which is equivalent to shifting the mask to the left.这将提取从 m 到 n 的位返回的值,使得 0 <= m <= n <= 7。这是通过将 myByte 向右移动 m 位来完成的,这相当于将掩码向左移动.

However, so far I've been unable to do something similar to set bits using a function with three arguments.但是,到目前为止,我一直无法使用具有三个参数的函数执行类似于设置位的操作。 The best I can do is to create the function:我能做的最好的就是创建函数:

BYTE setByteBits(BYTE n, BYTE m, BYTE b, BYTE c) {
    BYTE mask = ((0x01 << (n + 1)) - 1) << m;
    return (b & ~mask) | (c & mask);
}

where n and m are the same as before, b is the value of the original byte, and c is the value of some of the bits we want to change.其中 n 和 m 与之前相同,b 是原始字节的值,c 是我们要更改的某些位的值。 The update byte is returned.返回更新字节。 This would be called as:这将被称为:

BYTE num = setByteBits(n - m, m, MyByte, c << m);

but 4 rather than 3 arguments are needed, and rather than shifting myByte by m bits to the right, the mask is shifted to the left together with its complement in the function, as given be the 2nd argument m.但是需要 4 个而不是 3 个参数,并且不是将 myByte 向右移动 m 位,而是将掩码与函数中的补码一起向左移动,如第二个参数 m 所示。 Although as far as I can see this works correctly, so far all attempts to do something similar as getByteBits() with 3 arguments have failed.尽管据我所知,这可以正常工作,但到目前为止,所有尝试使用 3 个参数执行类似于 getByteBits() 的操作都失败了。

Does anybody have any idea about this?有人对此有任何想法吗? Also I would appreciate if any bugs can be found in the code.如果可以在代码中找到任何错误,我将不胜感激。 Incidentally, for setByteBits() I made use of the link:顺便说一句,对于 setByteBits() 我使用了链接:

How do you set only certain bits of a byte in C without affecting the rest? 如何在 C 中仅设置字节的某些位而不影响其余位?

Many thanks.非常感谢。

so far I've been unable to do something similar to set bits using a function with three arguments到目前为止,我一直无法使用具有三个参数的函数执行类似于设置位的操作

I do not understand your code, because you use so many m n c b one letter variables.我不明白你的代码,因为你使用了这么多m n c b一个字母的变量。 Maybe try to be more descriptive?也许尝试更具描述性? You don't have to write short code, there is no performance gain in that.您不必编写短代码,这不会提高性能。

When n is the stopping bit position inside the byte, 1 << (n + 1) will give you too big mask.n是字节内的停止位位置时, 1 << (n + 1)会给你太大的掩码。 You have to shift 1 of the length of the range of bits, and then that mask shift to the left by the start position.您必须将位范围的长度移动1 ,然后该掩码向左移动起始位置。 I mixed n with m so many times in your code, I do not know which is which.我在您的代码中多次将nm混合,我不知道哪个是哪个。

The following works, at least for tests I tried:以下工作,至少对于我尝试过的测试:

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

typedef unsigned char byte;
#define BYTE_BITS  CHAR_BIT
typedef uint_fast8_t bitpos;

/**
 * Set bits in the byte `thebyte`
 * between the range of bit `rangestart` inclusive to `rangestop` exclusive
 * counting from 0 from LSB
 * the the range of these bits inside `masktoset`.
 */
byte setByteBits(bitpos rangestart,
        bitpos rangestop,
        byte thebyte,
        byte masktoset) {
    assert(rangestop <= BYTE_BITS);
    assert(rangestart < rangestop);
    const bitpos rangelen = rangestop - rangestart;
    const byte rangemask = (1u << rangelen) - 1u;
    const byte mask = rangemask << rangestart;
    return (thebyte & ~mask) | (masktoset & mask);
}

int main() {
    const int tests[][5] = {
        { 4,6,0,0xff,0b00110000 },
        { 4,6,0,0b01010101,0b00010000 },
        { 4,6,0,0b01100101,0b00100000 },
        { 4,6,0xff,0b01000101,0b11001111 },
        { 0,8,0,0xff,0xff },
        { 0,8,0,0xab,0xab },
        { 0,4,0xfa,0xab,0xfb },
        { 0,4,0xab,0xcd,0xad },
        { 4,8,0xab,0xcd,0xcb },
        { 4,8,0xef,0xab,0xaf },
    };
    for (size_t i = 0; i <sizeof(tests)/sizeof(*tests); ++i) {
        const int *const t = tests[i];
        const byte r = setByteBits(t[0],t[1],t[2],t[3]);
        fprintf(stderr, "%d (%#02x,%#02x,%#02x,%#02x)->%#02x ?= %#02x\n",
            i,t[0],t[1],t[2],t[3],r,t[4]);
        assert(r == t[4]);
    }
}

Many thanks - I created a new project in Visual Studio 2022, then copied and pasted your code into an empty source file without modifications.非常感谢 - 我在 Visual Studio 2022 中创建了一个新项目,然后将您的代码复制并粘贴到一个空的源文件中,无需修改。

On compiling I get a couple of warning messages as follows:在编译时,我收到几条警告消息,如下所示:

Rebuild started...重建开始...

1>------ Rebuild All started: Project: test-binary2, Configuration: Debug x64 ------ 1>----- 重建全部启动:项目:test-binary2,配置:Debug x64 ------

1>main.c 1>main.c

1>C:\Users\jeffi\source\repos\test-binary2\main.c(44,25): warning C4477: 'fprintf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'size_t' 1>C:\Users\jeffi\source\repos\test-binary2\main.c(44,25): 警告 C4477: 'fprintf' : 格式字符串 '%d' 需要一个 'int' 类型的参数,但可变参数参数 1 的类型为“size_t”

1>C:\Users\jeffi\source\repos\test-binary2\main.c(44,25): message : consider using '%zd' in the format string 1>C:\Users\jeffi\source\repos\test-binary2\main.c(44,25): message : 考虑在格式字符串中使用 '%zd'

1>test-binary2.vcxproj -> C:\Users\jeffi\source\repos\test-binary2\x64\Debug\test-binary2.exe 1>test-binary2.vcxproj -> C:\Users\jeffi\source\repos\test-binary2\x64\Debug\test-binary2.exe

1>Done building project "test-binary2.vcxproj". 1>完成构建项目“test-binary2.vcxproj”。

========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ========== ==========全部重建:1成功,0失败,0跳过==========

Then on running I get the following output:然后在运行时我得到以下输出:

0 (0x4,0x6,00,0xff)->0x30 ?= 0x30 0 (0x4,0x6,00,0xff)->0x30 ?= 0x30

1 (0x4,0x6,00,0x55)->0x10 ?= 0x10 1 (0x4,0x6,00,0x55)-​​>0x10 ?= 0x10

2 (0x4,0x6,00,0x65)->0x20 ?= 0x20 2 (0x4,0x6,00,0x65)->0x20 ?= 0x20

3 (0x4,0x6,0xff,0x45)->0xcf ?= 0xcf 3 (0x4,0x6,0xff,0x45)->0xcf ?= 0xcf

4 (00,0x8,00,0xff)->0xff ?= 0xff 4 (00,0x8,00,0xff)->0xff ?= 0xff

5 (00,0x8,00,0xab)->0xab ?= 0xab 5 (00,0x8,00,0xab)->0xab ?= 0xab

6 (00,0x4,0xfa,0xab)->0xfb ?= 0xfb 6 (00,0x4,0xfa,0xab)->0xfb ?= 0xfb

7 (00,0x4,0xab,0xcd)->0xad ?= 0xad 7 (00,0x4,0xab,0xcd)->0xad ?= 0xad

8 (0x4,0x8,0xab,0xcd)->0xcb ?= 0xcb 8 (0x4,0x8,0xab,0xcd)->0xcb ?= 0xcb

9 (0x4,0x8,0xef,0xab)->0xaf ?= 0xaf 9 (0x4,0x8,0xef,0xab)->0xaf ?= 0xaf

When copying and pasting the output to the page for my reply, the lines are concatenated, so I added a newline after each line of output from both outputs.将输出复制并粘贴到我的回复页面时,这些行是连接的,因此我在两个输出的每一行输出之后添加了一个换行符。 Other than the extra spaces, is this what you get?除了额外的空间,这是你得到的吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM