[英]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.我在您的代码中多次将
n
与m
混合,我不知道哪个是哪个。
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.