我正在编写一个发送TCP报头的程序(模拟3次握手).我有一个变量,这个变量包含数据偏移(3位)、保留(4位)和9标志(9位)。我使用按位操作来设置位。问题是,我如何打印每一个这些比特?
我怎么打印这3位呢?变量:
u_int16_t reserved_ofs_flags;我发现这个问题类似,但答案只适用于最不重要的问题:我怎么打印一点?
发布于 2022-04-09 07:31:21
要从从位置N开始的unsigned值中提取P位,从0中提取最小有效位数,可以使用以下表达式:
unsigned x = (value >> P) & ((1U << (N - 1) << 1) - 1);备注:
N是编译时间常数,则在编译时计算表达式((1U << (N - 1) << 1) - 1)。N至少是1,最多是unsigned类型中的位数。((1U << N) - 1)是N类型中的位数,则更简单的表达式unsigned具有未定义的行为。P是12,N是3,所以您可以编写:unsigned x = (value >> 12) & 7;发布于 2022-04-09 06:11:03
您可以使用按位运算获取所需的位。
例如:
unsigned int a = 22; // 10110 in binary
printf("%d\n", a & 1); // get the bit in the 1's place (0)
printf("%d\n", (a >> 1) & 1); // get the bit in the 2's place (1)
printf("%d\n", (a >> 2) & 1); // get the bit in the 4's place (1)
printf("%d\n", (a >> 3) & 1); // get the bit in the 8's place (0)
printf("%d\n", (a >> 4) & 1); // get the bit in the 16's place (1)
// 3 in decimal is 11 in binary
printf("%d\n", a & 3); // get the bits in the 1's and the 2's places
// (2 in decimal, 10 in binary)
printf("%d\n", (a >> 1) & 3); // get the bits in the 2's and the 4's places
// (3 in decimal, 11 in binary)发布于 2022-04-09 09:19:08
如果我理解您的问题,并且您希望能够提取N位数的值(从1到sizeof(type) * CHAR_BIT),从P位置开始(从0到sizeof(type) * CHAR_BIT - 1),那么您可以使用以下方法提取该位的子集:
/** extract N bits from value starting at position P,
* counting from 0 for the least significant bit
*/
unsigned nbitsatp (unsigned value, unsigned N, unsigned P)
{
/* mask is N 1's bits */
unsigned mask = ~0u >> ((sizeof mask * CHAR_BIT) - N);
return (value >> (P - N + 1)) & mask;
}(注意:表示4字节unsigned,N从1到32,P是基于零的从0到31的范围)
上面,mask以所有比特1 (~0u)开始,然后从位的总数减去N (留下N 1的比特)。然后,value由P - N + 1移位,这样您就可以在P位置用相应的1位位数来AND所需的位数。由于两者都被移动,所以值开始于最小有效位,因此结果是N位在P位置的值。
这就避免了硬编码您想要的每一个位的数量和个别位位置。
在您的示例中,您希望从0111000000000000 (28672)中提取前3位,这将是positon P == 15上的3位N == 3,其结果是011 (3)。
--一个简短的示例
下面的示例使用unsigned作为类型,只要它在硬件上至少是2字节,对于uint16_t类型就足够了。
#include <stdio.h>
#include <limits.h>
/** extract N bits from value starting at position P,
* counting from 0 for the least significant bit
*/
unsigned nbitsatp (unsigned value, unsigned N, unsigned P)
{
/* mask is N 1's bits */
unsigned mask = ~0u >> ((sizeof mask * CHAR_BIT) - N);
return (value >> (P - N + 1)) & mask;
}
int main (void) {
unsigned v, n, p;
fputs ("enter v, n, p : ", stdout); /* prompt for v, n, p */
/* read/validate positive int value */
if (scanf ("%u%u%u", &v, &n, &p) != 3) {
fputs ("error: invalid unsigned integer input.\n", stderr);
return 1;
}
/* output result */
printf ("\nvalue of %u bits at pos %u in %u is : %u\n",
n, p, v, nbitsatp (v, n, p));
}示例使用/输出
您希望3位开始于28672的15位置的具体示例
$ ./bin/nbitsatp
enter v, n, p : 28672 3 15
value of 3 bits at pos 15 in 28672 is : 3或者让我们把前4位放在第15位,0111 (7):
$ ./bin/nbitsatp
enter v, n, p : 28672 4 15
value of 4 bits at pos 15 in 28672 is : 7或从第15位置开始的前5位:
$ ./bin/nbitsatp
enter v, n, p : 28672 5 15
value of 5 bits at pos 15 in 28672 is : 14或者,在您的示例中,9-标志(9位,位置8)的值将为零。
$ ./bin/nbitsatp
enter v, n, p : 28672 9 8
value of 9 bits at pos 8 in 28672 is : 0使用预定义的宏检索想要的位
使用nbitsatp()函数检索您感兴趣的位的一种方便方法是为您想要获得的每一组位设置一个#define宏。例如,要获得数据偏移量的3位、保留的4位和9位标志集,您可以定义三个宏,这些宏设置位数和位置,允许您将TCP头值简单地作为参数传递。
/* macros for 3-bit offset, 4-bit reserved, 9-bit flags */
#define HDR_OFFSET(TCPHDRVAL) nbitsatp ((TCPHDRVAL), 3, 15)
#define HDR_RESERVED(TCPHDRVAL) nbitsatp ((TCPHDRVAL), 4, 12)
#define HDR_FLAGS(TCPHDRVAL) nbitsatp ((TCPHDRVAL), 9, 8)要获得所需的位,只需调用传递TCP标头值的宏作为参数。
int main (void) {
unsigned v;
fputs ("enter TCP hdr value : ", stdout); /* prompt TCP HDR VAL */
/* read/validate TCP header value */
if (scanf ("%u", &v) != 1) {
fputs ("error: invalid unsigned integer input.\n", stderr);
return 1;
}
/* output result */
printf ("\n data offset bits : %u\n"
" reserved bits : %u\n"
" flag bits : %u\n",
HDR_OFFSET (v), HDR_RESERVED (v), HDR_FLAGS (v));
}输出
$ /bin/nbitsatp_macro
enter TCP hdr value : 28672
data offset bits : 3
reserved bits : 8
flag bits : 0如果需要,可以以简单的方式输出3 (011)、8 (1000)和标志(000000000)的填充二进制表示。请参阅函数中的binprnpad()函数
https://stackoverflow.com/questions/71805577
复制相似问题