c - 从命令行参数C将十六进制转换为二进制

标签 c binary hex

这是一个家庭作业,在终端调用命令时,我必须将十六进制转换为二进制。我的“老师”不是真正的“老师”,所以我完全迷路了。我必须包含一个过程void printBits(unsigned long I),它在I中打印位。它将使用'-p'开关从命令行调用,后跟一个32位的十六进制无符号长整数。示例:$lab3-p 0x5
产量:0000 0000 0000 0000 0000 0000 0101
请不要只给我密码。我要明白这一点。

void printBits(unsigned long number) {
    // Declare Array to hold our binary number
    char binaryNumber[32];
    // For Loop Index
    int i;
    for (i = 31; i >= 0; --i)
    {
    binaryNumber[i] = (number & 1);
    number >>= 1;
    }

最佳答案

有很多方法可以打印任何数字的二进制表示。首先,您可以直接输出移位和索引操作的结果(到stdout,一个文件,等等…)。这似乎是您开始使用的方法,但随后您声明了一个32位缓冲区。虽然您当然可以这样做,但如果不返回指向已完成缓冲区的指针,则不需要缓冲结果。(这就引出了我下面的第三点)
简单地输出位而不存储/返回指向以nul结尾的字符串中的位的指针,有它的位置,但通常用途有限。然而,这是一个共同的问题,包含了所有方法的基础。创建未添加的二进制表示法的方法如下:

/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
    if (!v)  { putchar ('0'); return; };  /* if v = 0 output '0' */

    size_t sz = sizeof v * CHAR_BIT;  /* get the number of bits in v */
    unsigned long rem = 0;        /* variable to hold shifted result */

    while (sz--)               /* for each bit (in decreasing order) */
        if ((rem = v >> sz))   /* if bits exist in the shifted value */
            putchar ((rem & 1) ? '1' : '0');    /* output '1' or '0' */
}

这些评论很有解释性。该方案是以32位数字的最高有效位(例如,位31(31-0))开始移动每个位。检查移位后是否有任何1位(如果没有,则移位超过数字中最有效的位位置,无需打印)。一旦在rem中找到一个位,在循环迭代的其余部分中总会有位要打印,因为您正在以递减的量移动。从最有意义的位开始(首先打印),你的位以正确的顺序打印出来,并且只打印组成这个数字的位数。
通常,当您只是直接将二进制表示输出到屏幕时,您只希望输出最高有效位的位。(这可以防止输出一个前面有63个“cc>”的“a1”,使事情变得一团糟。)
下一步,是将填充的二进制表示输出到一些位。如果您只想查看任意数字中较低的0位,但希望每次都有固定位数的表示,那么这非常有用。在这里,您只需传递希望查看的位数。然后,您的函数将循环遍历您的数字中的位数位置,并输出结果:
/** 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) putchar ((v & 1) ? '1' : '0');  /* if no sz, '0' is fine */

    if (sz > sizeof v * CHAR_BIT)  /* if sz exceed # of bits, limit   */
        sz = sizeof v * CHAR_BIT;

    while (sz--)  /* for sz positions in decreasing order, '1' or '0' */
        putchar ((v >> sz & 1) ? '1' : '0');
}

您将注意到这里的主要区别是,您不必担心检查位是否保留以防止打印不需要的前导零,因为您使用参数8, 16, 32, ...控制位的数量。(如果通过sz大小,由您决定如何操作,我只选择输出0
现在谈上面提到的第三点。从代码主体的格式化角度来看,简单地输出位是很麻烦的。我发现将位存储在字符数组中(以nul结尾,因此可以将其视为字符串)并返回指向数组的指针,以便将其传递给'0'等更有用。现在,您要么必须将大小适当的数组作为参数传递,声明printf数组,以便在函数返回时不会破坏数组,或者为函数内的数组动态分配存储空间。所有这些都有优缺点,根据代码的需要,您必须权衡它们。例如。:
/** returns pointer to binary representation of 'v' zero padded to 'sz'.
 *  returns pointer to string contianing binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits.
 */
char *binpad (const unsigned long v, const size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *--p = (v>>i & 1) ? '1' : '0';

    return p;
}

代码的功能与上面的非缓冲填充对应代码相同。注意static如何返回缓冲区中p位数开始的起始位置。还要注意,您需要一个常量来表示硬件上asz中的位数。(通常以类似于BITS_PER_LONG的方式处理)
注意:只需注意,对long声明的一个限制是转换函数在任何一个BUILD_64调用中(或在任何一行代码中)只能使用一次,因为只有一个存储数组用于二进制转换。(在进行static调用之前,您始终可以进行任意数量的调用,并将结果存储在不同的位置)
二进制打印的最后一个变化是使用包含分隔符的打印表示,以便更容易识别和比较二进制字符串(特别是在处理较长的printfprintf序列时。例如:
hexval : 0xdeadbeef  =>  11011110-10101101-10111110-11101111

该函数的工作原理与上面的0基本相同,但添加了静态缓冲区以容纳分隔符,并额外检查位位置以确定何时应向缓冲区添加分隔符:
/** returns pointer to formatted binary representation of 'v' zero padded to 'sz'.
 *  returns pointer to string contianing formatted binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
 *  'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
 */
char *binfmt (const unsigned long v, const unsigned char sz, 
            const unsigned char szs, const char sep)
{
    static char s[BITS_PER_LONG * 2 + 1] = {0};
    char *p = s + 2 * BITS_PER_LONG;
    register size_t i;

    *p = 0;
    for (i = 0; i < sz; i++) {
        p--;
        if (i > 0 && szs > 0 && i % szs == 0)
            *p-- = sep;
        *p = (v >> i & 1) ? '1' : '0';
    }

    return p;
}

问题的其余部分只是处理命令行参数,并执行从输入字符串到无符号值的转换,以及验证该数字是否不超过32位等。。您可以使用1处理参数,也可以使用循环处理少量简单选项。在Linux上,您的代码应该响应的唯一必需参数是binpad以获取帮助,而getops以获取版本。虽然没有人这样做的简短例子等,它至少是好的,有这些信息。请看下面的示例,它将所有部分组合在一起,如果您有任何问题,请告诉我:
#include <stdio.h>
#include <stdlib.h> /* for strtoul */
#include <errno.h>  /* for errno   */
#include <limits.h> /* for UINT_MAX, ULONG_MAX, CHAR_BIT */

#define PACKAGE "hex2bin"
#define VERSION "0.01"

/* BUILD_64 - Check x86/x86_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif

unsigned long processopts (int argc, char **argv);
unsigned long xstrtoul (char *s);
void binprn (const unsigned long v);
void binprnpad (const unsigned long v, size_t sz);
char *binpad (const unsigned long v, const size_t sz);
char *binfmt (const unsigned long v, const unsigned char sz, 
            const unsigned char szs, const char sep);
void help (int xcode);

int main (int argc, char **argv) {

    unsigned long hexval = processopts (argc, argv);

    /* print unpadded binary */
    printf ("\n hexval : 0x%lx (%lu)  =>  ", hexval, hexval);
    binprn (hexval);
    printf ("\n");

    /* print padded to 32-bits */
    printf ("\n hexval : 0x%lx (%lu)  =>  ", hexval, hexval);
    binprnpad (hexval, sizeof (int) * CHAR_BIT);
    printf ("\n");

    /* padded binary returned as formatted string
     * with '-' separators every 8 bits
     */
    printf ("\n hexval : 0x%lx (%lu)  =>  %s\n\n", hexval, hexval,
            binfmt (hexval, sizeof (int) * CHAR_BIT, CHAR_BIT, '-'));

    return 0;
}

/* quick custom argument handler */
unsigned long processopts (int argc, char **argv)
{
    size_t i = 1;
    unsigned long val = 0;

    if (argc < 2) help (0);         /* insufficient arguments       */

    for (; argv[i]; i++) {          /* for each argument            */
        if (*argv[i] == '-') {      /* for each beginning with '-'  */
            switch (argv[i][1]) {
                case 'h':           /* respond to '-h' help         */
                    help (0);
                case 'p':           /* handle '-p' convert value    */
                    if (!argv[i+1]) {   /* if '-p' w/o next arg     */
                        fprintf (stderr, "error: insufficient input.\n");
                        help (1);
                    }
                    if (*argv[i+1] != '0' || /* validate hex input  */
                        (argv[i+1][1] != 'x' && argv[i+1][1] != 'X')) {
                        fprintf (stderr, "error: invalid 'hex_value' input.\n");
                        help (1);                    
                    }
                    val = xstrtoul (argv[i+1]); /* convert to ulong */
                    if (val > UINT_MAX) {       /* validate 32-bits */
                        fprintf (stderr, "error: input value exceeds 32-bits.\n");
                        help (1);
                    }
                    break;
                case 'v':           /* respond to '-v' version      */
                    printf ("%s, version %s\n", PACKAGE, VERSION);
                    exit (0);
                default :
                    fprintf (stderr, "error: invalid/unrecognized option '%s'.\n",
                            argv[i]);
                    help (1);
            }
        }
    }
    return val; /* return val */
}

unsigned long xstrtoul (char *s)
{
    unsigned long v = 0;
    errno = 0;

    /* test for hex or decimal conversion */
    if (*s == '0' && (s[1] == 'x' || s[1] == 'X'))
        v = strtoul (s, NULL, 16);
    else
        v = strtoul (s, NULL, 10);

    /* check for various possible errors */
    if ((errno == ERANGE && v == ULONG_MAX) || (errno != 0 && v == 0)) {
        perror ("strtoul");
        exit (EXIT_FAILURE);
    }
    return v;
}

/** unpadded binary representation of 'v'. */
void binprn (const unsigned long v)
{
    if (!v)  { putchar ('0'); return; };

    size_t sz = sizeof v * CHAR_BIT;
    unsigned long rem = 0;

    while (sz--)
        if ((rem = v >> sz))
            putchar ((rem & 1) ? '1' : '0');
}

/** 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) putchar ((v & 1) ? '1' : '0');

    if (sz > sizeof v * CHAR_BIT)
        sz = sizeof v * CHAR_BIT;

    while (sz--)
        putchar ((v >> sz & 1) ? '1' : '0');
}

/** returns pointer to binary representation of 'v' zero padded to 'sz'.
 *  returns pointer to string contianing binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits.
 */
char *binpad (const unsigned long v, const size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *--p = (v>>i & 1) ? '1' : '0';

    return p;
}

/** returns pointer to formatted binary representation of 'v' zero padded to 'sz'.
 *  returns pointer to string contianing formatted binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
 *  'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
 */
char *binfmt (const unsigned long v, const unsigned char sz, 
            const unsigned char szs, const char sep)
{
    static char s[BITS_PER_LONG * 2 + 1] = {0};
    char *p = s + 2 * BITS_PER_LONG;
    register size_t i;

    *p = 0;
    for (i = 0; i < sz; i++) {
        p--;
        if (i > 0 && szs > 0 && i % szs == 0)
            *p-- = sep;
        *p = (v >> i & 1) ? '1' : '0';
    }

    return p;
}

void help (int xcode)
{
    xcode = xcode ? xcode : 0;  /* set default exit code */

    printf ("\n %s, version %s\n\n"
            "  usage:  %s -p hex_value (32-bit)\n\n"
            "  converts 'hex_value' to its binary representation.\n\n"
            "    Options:\n\n"
            "      -h            this help.\n"
            "      -p hex_value  display binary representation of 'hex_value'.\n"
            "      -v            display version information.\n\n",
            PACKAGE, VERSION, PACKAGE);

    exit (xcode);
}

使用/输出
$ ./bin/hex2bin -p 0xe7

 hexval : 0xe7 (231)  =>  11100111

 hexval : 0xe7 (231)  =>  00000000000000000000000011100111

 hexval : 0xe7 (231)  =>  00000000-00000000-00000000-11100111


$ ./bin/hex2bin -p 0xdeadbeef

 hexval : 0xdeadbeef (3735928559)  =>  11011110101011011011111011101111

 hexval : 0xdeadbeef (3735928559)  =>  11011110101011011011111011101111

 hexval : 0xdeadbeef (3735928559)  =>  11011110-10101101-10111110-11101111


$ ./bin/hex2bin -h

 hex2bin, version 0.01

  usage:  hex2bin -p hex_value (32-bit)

  converts 'hex_value' to its binary representation.

    Options:

      -h            this help.
      -p hex_value  display binary representation of 'hex_value'.
      -v            display version information.


$ ./bin/hex2bin -v
hex2bin, version 0.01

关于c - 从命令行参数C将十六进制转换为二进制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35500171/

相关文章:

c - GtkSourceGutter - 如何在特定行上呈现图标或文本

c - 我已经编写了一个代码来将摄氏度转换为华氏度,但是输出太大了

Char 等于 C 中的 char 变量

xcode - iTunes Connect 和 Xcode 8 : your app has changed to invalid binary

SQL 将数字转换为任何基数的字符串表示形式(二进制、十六进制、...、三十六进制)

无法用函数指针填充 double 组

python - 二进制到 Python 中的字符串/文本

c - 为什么我不能在C编程中将char写入二进制文件?

python,十六进制值转换为字符串/整数

Golang Base64 到 Hex 转换