首页 > 解决方案 > 将十六进制字符 IP 转换为二进制

问题描述

几天前我问了一个问题,它对我有很大帮助,但我又有一个问题。我没有得到的是当我将十六进制输入作为 scanf("%c%c.%c%c.%c%c.%c%c%c") 我如何将其转换为二进制时。我想说的是,假设我输入为 00.11.10.FF 我如何将其转换为 00000000.00010001.00010000.11111111 并像这样打印。

如果你能帮助我,我会很高兴。

标签: c

解决方案


如果您仍然遇到问题,如评论中所述,除非您想创建一个查找表(这是一个很好的方法),您的第一个任务是将 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;
    }

注意:您可以声明hexunsigned char并保存额外的字节,但是您可能希望通过scanf使用hh 类型修饰符来限制读取的值,例如"%hhx",但是旧版本的 VS 不支持该前缀,所以在这种情况下unsigned而是使用简单)

将十六进制字符转换为数值后,剩下的就是输出每个字符的二进制表示(即已经存储在内存中的值)。为此,您可以简单地循环和移位,检查该位是否为0or1并输出相应的字符'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"  };

然后该方案很简单,从用户那里读取一个字符,如果该字符c0-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;
}

(输出相同)

只是给同一只猫剥皮的另一种方法。如果您还有其他问题,请仔细查看并告诉我。


推荐阅读