[英]C Convert Large Integer To Binary
我有一个以21211328形式出现的IP地址。
我想将这个整数转换为二进制形式。
我现在遇到的问题是,基于示例-62674752,我的函数退出了。
这显然是错误的,因为它不能为负,也不是二进制的。
我正在使用的功能如下所示:
int toBinary(int decimalNo){
if (decimalNo == 0) return 0;
if (decimalNo == 1) return 1; /* optional */
return (decimalNo % 2) + 10 * toBinary(decimalNo / 2);
}
我使用它如下:
int num_converted = toBinary(iph->saddr); // convert it to binary
printk(KERN_INFO "BSADDR: %d", num_converted); // print the binary conversion to kernel for debugging
if ((num_converted & mask_array) == masked_sub){
return NF_DROP;
}
如上所述,这将在我的内核日志中返回错误的输出。
iph-> saddr返回21211328,int num_converted = toBinary(iph-> saddr); 返回-62674752。
首先,通常将IP地址表示为(供人类使用)单个字节的四重字节(按网络字节顺序由点分隔的四个数字),而不是二进制序列。
您发布的地址(21211328)代表地址1.67.168.192
(我想这是一种错误的表示方式-您需要考虑到所有ip地址均以网络字节顺序排列,最重要的字节在前-地址的192.168.67.1
)
要成功解码ip地址,您首先必须考虑机器将以正确的字节序对待它,还是必须切换字节才能将其解释为数字。 地址192.168.67.1
的正确整数(十进制)将是3,232,252,673
。 此数字不能表示为有signed int
,因为它具有最高有效位,因此将其表示为负数。
要解码IP地址,首先必须使用ntohl(3)
函数将从套接字接口获得的数字转换为主机字节顺序(字节序)。 一旦获得主机字节顺序的地址,就必须将数字转换为以256为基数。这非常容易,您可以使用以下代码片段进行操作:
unsigned long ip_address = ntohl(server_address.sin_addr.s_addr);
int i;
for (i = 24; i >= 0; i -= 8) {
if (i < 24) printf("."); /* print the dot between the numbers */
printf("%d",
(ip_address >> i) & 0xff);
}
我将在下面解释:
表达式(ip_address >> i) & 0xff
表示将第24至31位右移i
位(或24
位, 16
位, 8
位和0
位)。 因此,首先我们将8个最高有效位放在0到7的位置( 24..31 => 0..7
),接下来我们对它们旁边的位进行处理( 16..23 => 0..7
),依此类推,直到最低有效位都完全不移位( 0..7 => 0..7
)。 一旦有了对位置0..7
感兴趣的位,我们就用0xff
对其进行屏蔽(这是在位位置0..7
值为1
s的值,而在其他位置0..7
0
s),因此and位运算符&
将仅保留我们已经移动到固定位置0..7
,将掩盖所有其他位。 因此,我们最终得到的数字介于0到255之间,这就是我们要打印的内容。
如果确实要以二进制形式表示它们,则可以通过稍微修改上面的代码来做到这一点,只需考虑将一个位数作为数字而不是八个位数:
unsigned long ip_address = ntohl(server_address.sin_addr.s_addr);
for (i = 31; i >= 0; i--) {
/* In this case, we don't print the dot between the numbers */
printf("%d",
(ip_address >> i) & 0x1);
}
这次的掩码为0x01
,仅掩码数字的最低有效位。
最后,我编写了一个完整的程序来说明两种解码方式,另外还展示了ntohl(3)
函数的用法:
/* 00001 */ #include <arpa/inet.h>
/* 00002 */ #include <stdio.h>
/* 00003 */ #ifndef DOTTED_DECIMAL
/* 00004 */ #define DOTTED_DECIMAL 1
/* 00005 */ #endif
/* 00006 */ #if DOTTED_DECIMAL
/* 00007 */ # define NBITS 8
/* 00008 */ # define SEP "."
/* 00009 */ #else /* BINARY */
/* 00010 */ # define NBITS 1
/* 00011 */ # define SEP ""
/* 00012 */ #endif
/* 00013 */ #define MASK ((1 << NBITS) - 1) /* 100..00 - 1 = 011..11, with NBITS `1` bits */
/* 00014 */ char *ip_formatted(long ip, char *sep, char *buff, size_t buffsz);
/* 00015 */ int main()
/* 00016 */ {
/* 00017 */ char line[1024];
/* 00018 */ unsigned long ip_netfmt = 21211328; /* this was the ip you posted (in network byte order) */
/* 00019 */ unsigned long ip_hostfmt = ntohl(ip_netfmt); /* this is the ip in host byte order */
/* 00020 */ printf("%lu => [%s]\n", ip_netfmt, ip_formatted(ip_netfmt, SEP, line, sizeof line));
/* 00021 */ printf("%lu => [%s]\n", ip_hostfmt, ip_formatted(ip_hostfmt, SEP, line, sizeof line));
/* 00022 */ }
/* 00023 */ char *ip_formatted(long ip, char *sep, char *buff, size_t buffsz)
/* 00024 */ {
/* 00025 */ size_t n;
/* 00026 */ char *s = buff;
/* 00027 */ int i;
/* 00028 */ for (i = 32 - NBITS; i >= 0; i -= NBITS) {
/* 00029 */ int digit = (ip >> i) & MASK;
/* 00030 */ n = snprintf(s, buffsz,
/* 00031 */ "%s%d",
/* 00032 */ i == 32 - NBITS ? "" : sep,
/* 00033 */ digit);
/* 00034 */ s += n; buffsz -= n;
/* 00035 */ }
/* 00036 */ return buff;
/* 00037 */ }
使用以下命令编译此代码:
$ cc -o ipaddr -DDOTTED_DECIMAL=1 ipaddr.c
查看以点分十进制显示的输出,以及
$ cc -o ipaddr -DDOTTED_DECIMAL=0 ipaddr.c
查看二进制输出。
(我提供了行号,因此可以使用对代码的引用和注释,因此您可以通过剪切和粘贴直接编译代码)
尝试这个:
#include <stdio.h>
char *getBin( unsigned long val) {
static char buf[33];
int i;
buf[32]='\0';
for(i=31; i>=0; i--){
buf[i] = val & 1?'1':'0';
val/=2;
}
return buf;
}
int main()
{
unsigned long ip=0x80e2d301;
printf( " ip:%08lx, bin:%sB\n", (unsigned long)ip, getBin(ip) );
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.