c - 将十六进制字符 IP 转换为二进制
问题描述
几天前我问了一个问题,它对我有很大帮助,但我又有一个问题。我没有得到的是当我将十六进制输入作为 scanf("%c%c.%c%c.%c%c.%c%c%c") 我如何将其转换为二进制时。我想说的是,假设我输入为 00.11.10.FF 我如何将其转换为 00000000.00010001.00010000.11111111 并像这样打印。
如果你能帮助我,我会很高兴。
解决方案
如果您仍然遇到问题,如评论中所述,除非您想创建一个查找表(这是一个很好的方法),您的第一个任务是将 ASCII 字符"00.11.10.FF"
转换为0x0, 0x11, 0x10 & 0xff
. 有很多方法可以做到这一点,但是如果您正在阅读scanf
,您也可以scanf
通过阅读"%x"
格式说明符来为您完成它,该说明符将接受十六进制字符并执行转换。
例如,要将每个四边形读入unsigned
名为 的值数组hex
,您可以执行以下操作:
#define QUAD 4u /* if you need a constant, #define one (or more) */
...
unsigned hex[QUAD] = {0}; /* let's input the values as numbers */
...
if (scanf ("%x.%x.%x.%x", &hex[0], &hex[1], &hex[2], &hex[3]) != 4) {
fputs ("error: invalid input.\n", stderr);
return 1;
}
(注意:您可以声明hex
为unsigned char
并保存额外的字节,但是您可能希望通过scanf
使用hh
类型修饰符来限制读取的值,例如"%hhx"
,但是旧版本的 VS 不支持该前缀,所以在这种情况下unsigned
而是使用简单)
将十六进制字符转换为数值后,剩下的就是输出每个字符的二进制表示(即已经存储在内存中的值)。为此,您可以简单地循环和移位,检查该位是否为0
or1
并输出相应的字符'0'
or '1'
。
此外,由于一个简单的循环和移位只会在没有1's
剩余位之前输出,因此您需要设置要显示的位数,以确保通过循环该次数获得完整的每字节 8 位。将信息写入stdout
请求的位数的便捷函数可以是:
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 1 - sizeof v * CHAR_BIT.
*/
void binprnpad (const unsigned long v, size_t sz)
{
if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
if (!v) { while (sz--) putchar ('0'); return; }
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
(CHAR_BIT
是一个表示每字节位数的宏,可在 中找到limits.h
)
总而言之,你可以这样做:
#include <stdio.h>
#include <limits.h>
#define QUAD 4u /* if you need a constant, #define one (or more) */
#define QBITS 8u
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
*/
void binprnpad (const unsigned long v, size_t sz)
{
if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
if (!v) { while (sz--) putchar ('0'); return; }
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
int main (void) {
unsigned hex[QUAD] = {0}; /* let's input the values as numbers */
fputs ("enter hex IP: ", stdout); /* read/validate input */
if (scanf ("%x.%x.%x.%x", &hex[0], &hex[1], &hex[2], &hex[3]) != 4) {
fputs ("error: invalid input.\n", stderr);
return 1;
}
for (unsigned i = 0; i < QUAD; i++) { /* loop over each quad */
if (i) /* if not zero output the '.' */
putchar ('.');
binprnpad (hex[i], QBITS); /* output the 8-bits per quad */
}
putchar ('\n'); /* tidy up with newline */
return 0;
}
示例使用/输出
$ ./bin/hexip2bin
enter hex IP: 00.11.10.FF
00000000.00010001.00010000.11111111
只读字符——查找表方法
如果您只能读取字符而不能读入数组或字符串,那么最简单的方法是简单地读取一个字符并从一个包含二进制表示0 - 15
(或[0-9A-F]
换句话说)的简单表中查找其二进制表示。
查找表可以是一个简单的全局,例如
/* lookup table for hex byte binary representations */
char *lookup[] = { "0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111" };
然后该方案很简单,从用户那里读取一个字符,如果该字符c
是0-9
,则只输出lookup[c - '0']
(其中c - '0'
的结果是数字0-9
参见:ASCIITable.com)。如果字符c
被[A-F]
输出(它减去查找表中索引lookup[c - '7']
的 ASCII 字符值)。否则,如果字符是 a ,则将其原样输出。'7'
10-15
'.'
为了防止有人进入"00.11.10.ff"
,只需将所有读取的字符转换为大写,并toupper()
提供 in (或手动ctype.h
清除第 6 位)。[a-f]
这很简单。你甚至不需要scanf
,只是getchar();
,例如
#include <stdio.h>
#include <ctype.h>
#define QBYTES 8u /* if you need a constant, #define one */
/* lookup table for hex byte binary representations */
char *lookup[] = { "0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111" };
int main (void) {
unsigned ndx = 0; /* index of the hex byte read */
fputs ("enter hex IP: ", stdout); /* read/validate input */
while (ndx < QBYTES) { /* read until 8 hex bytes read */
unsigned char c = toupper(getchar()); /* read char as upper-case */
if (isdigit (c)) { /* if [0-9] */
fputs (lookup[c - '0'], stdout);
ndx++; /* increment index */
}
else if (isxdigit (c)) { /* if [A-F] */
fputs (lookup[c - '7'], stdout);
ndx++;
}
else if (c == '.') /* if '.' */
putchar (c);
else { /* handle character not [0-9A-F.] */
fputs ("(error: invalid character input)\n", stderr);
break;
}
}
putchar ('\n'); /* tidy up with newline */
return 0;
}
示例使用/输出
$ ./bin/hexip2bin
enter hex IP: 00.11.10.FF
00000000.00010001.00010000.11111111
小写十六进制示例:
$ ./bin/hexip2bin
enter hex IP: 00.11.10.ff
00000000.00010001.00010000.11111111
读一个char
输出一个半字节
而且,当然,您始终可以在这些方法之间进行混合和匹配。如果您不能使用查找表,则只需获取字符的数值并将表示该十六进制值的 4 位写入输出,例如
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#define QUAD 4u /* if you need a constant, #define one (or more) */
#define QBYTES 8u
/** binary representation of 'v' padded to 'sz' bits.
* the padding amount is limited to the number of
* bits in 'v'. valid range: 1 - sizeof v * CHAR_BIT.
*/
void binprnpad (const unsigned long v, size_t sz)
{
if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
if (!v) { while (sz--) putchar ('0'); return; }
if (sz > sizeof v * CHAR_BIT)
sz = sizeof v * CHAR_BIT;
while (sz--)
putchar ((v >> sz & 1) ? '1' : '0');
}
int main (void) {
unsigned ndx = 0; /* index of the hex byte read */
fputs ("enter hex IP: ", stdout); /* read/validate input */
while (ndx < QBYTES) { /* read until 8 hex bytes read */
unsigned char c = toupper(getchar()); /* read char as upper-case */
if (isdigit (c)) { /* if [0-9] */
binprnpad (c - '0', QUAD);
ndx++;
}
else if (isxdigit (c)) { /* if [A-F] */
binprnpad (c - '7', QUAD);
ndx++;
}
else if (c == '.') /* if '.' */
putchar (c);
else { /* handle character not [0-9A-F.] */
fputs ("(error: invalid character input)\n", stderr);
break;
}
}
putchar ('\n'); /* tidy up with newline */
return 0;
}
(输出相同)
只是给同一只猫剥皮的另一种方法。如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- amazon-web-services - 在不同的 AWS 区域中创建 RDS 只读副本时是否会复制/复制安全组?
- python - 能够导入模块但不能从中导入东西
- javascript - 在模块中使用 import 导入变量或使用 const 定义变量有我不理解的行为
- javascript - 打字稿:比较两个具有公共键的不同对象数组并从源数组中获取公共对象
- sql - Postgres:开发过程是怎样的?
- javascript - JavaScript - 将 eventListener 添加到具有类型范围的所有输入
- python - 如何替换 Python 中键的值?
- java - Javafx 图标图像未加载
- c# - NotiIcon 的 ContextMenuStrip 的拐角处需要重写哪个方法?
- javascript - Mocha 错误:“isNumberPrime”函数不是函数错误