从命令行参数C将十六进制转换为二进制 [英] Convert hex to binary from command line arguments C

查看:81
本文介绍了从命令行参数C将十六进制转换为二进制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一项家庭作业,在终端中调用命令时,我必须将十六进制转换为二进制.我的老师"不是真正的教学" C,所以我迷路了.我必须包含一个过程void printBits(unsigned long i),该过程将打印i中的位.将在命令行中使用"-p"开关调用它,然后是一个十六进制形式的32位无符号长整数.例如:$ lab3 -p 0x5

This is a homework assignment where I have to convert hex to binary when a command is called in the terminal. My "teacher" isn't really "teaching" C so I'm dead lost. I have to include a procedure, void printBits(unsigned long i), that prints the bits in i. It will be invoked from the command line using the '-p' switch followed by a 32-bit unsigned long integer in hex form. EX: $ lab3 -p 0x5

输出:0000 0000 0000 0000 0000 0000 0000 0101

Output: 0000 0000 0000 0000 0000 0000 0000 0101

请不要只给我代码.我需要了解这一点.

Please don't just give me the code. I need to understand this.

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位缓冲区.虽然可以肯定地做到这一点,但是如果您不打算将指针返回到已完成的缓冲区,则无需缓冲结果. (将我带到下面的第三点)

There are a number of ways to approach printing the binary representation for any number. First, you can simply output the result of your shift and index operation directly (to stdout, a file, etc...) This seems to be the approach you began with, but then you declared a 32 bit buffer. While you can certainly do that, there is no need to buffer the results if you are not going to return a pointer to the completed buffer. (that brings me to my 3rd point, below)

仅输出位而不存储/返回指向以 nul结尾的字符串中的位的指针,虽然它有其位置,但通常用途有限.但是,这是一个普遍问题,涉及所有方法的基础.创建未填充的二进制表示形式的方法如下:

Simply outputting bits without storing/returning a pointer to the bits in a nul-terminated string, has its place but is generally of limited use. Nevertheless, it is a common problem that encompasses the basics of all approaches. Creating an unpadded binary representation can be approached as follows:

/** 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中找到了某个位,则在循环迭代的其余部分中总会有要打印的位,因为您的移位量减小了.使用最高有效位(先打印),最后以正确的顺序打印出位,只打印组成该位的位数.

The comments are fairly explanatory. The scheme is to shift each bit beginning with the most significant bit (e.g. bit 31 (31-0) for a 32-bit number. You check whether there are any 1-bits following the shift (if not, the shift exceeds the most significant bit position in the number and nothing need be printed). Once there is a bit found in rem, there will always be bits bits to print throughout the remainder of the loop iterations because you are shifting by a decreasing amount. By starting with the most significant bit (which prints first), you end up with your bits printed out in the correct order and only printing the number of bits that make up the number.

通常,当您仅将二进制表示形式直接输出到屏幕时,您只希望输出最高有效位的位. (这会阻止在其前面输出带有63个01,使事情变得一团糟.)

Generally when you are simply outputting the binary representation directly to the screen, you will only want to output bits up to the most significant bit. (which prevents outputting a 1 with 63 0's in front of it making a mess out of things.)

下一步,将填充的二进制表示形式输出到一定数量的位.如果您只想查看任意数量的低位8, 16, 32, ...位,但每次都希望使用固定位数的表示形式,这将很有用.在这里,您只需传递希望查看的位数.然后,您的函数将循环遍历您数字中的那个位数,并输出结果:

Next, is outputting a padded binary representation to some number of bits. This is useful if you just want to look at the lower 8, 16, 32, ... bits in any number, but want a representation with a fixed number of bits each time. Here you simply pass the number of bits you wish to look at. Your function will then loop over that number of bit-positions in your number and output the results:

/** 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');
}

您会注意到这里的主要区别在于您不必担心检查位是否剩余以防止打印不需要的前导零,因为您正在使用参数sz控制位的数量. (由您决定是否通过0大小,我只是选择输出'0')

You will notice the primary difference here is that you do not have to concern yourself with checking whether bits remain to prevent printing unwanted leading zeros, because you are controlling the number of bits with the parameter sz. (it's up to you what you do if a 0 size is passed, I just choose to output '0')

现在是上面提到的第三点.从格式化的角度来看,仅在代码主体中简单地输出位是很麻烦的.我发现将位存储在字符数组(<以nul结尾的,以便可以将其视为字符串)中并返回指向该数组的指针,以便将其传递给printf更为有用.等等.现在,您要么必须传递足够大小的数组作为参数,要么声明一个static数组,以便在函数返回时不破坏该数组,或者在函数内为该数组动态分配存储空间.所有这些都有其优缺点,您必须根据代码的需要进行权衡.例如:

Now for the third point mentioned above. Simply outputting bits is cumbersome from a formatting standpoint back in the main body of your code. I find it far more useful to store the bits in a character array (nul-terminated so it can be treated as a string) and return a pointer to the array so it can be passed to printf, etc. Now you either have to pass an adequately sized array as a parameter, declare a static array so the array isn't destroyed on function return, or dynamically allocate storage for the array within the function. All have pluses and minuses that you have to weigh depending upon the needs of your code. e.g.:

/** 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;
}

该代码的功能与上面的非缓冲填充代码相同.请注意p如何在sz位数开始的缓冲区内返回 内的起始位置.另请注意,您将需要一个BITS_PER_LONG常量,以表示硬件上long中的位数. (通常以类似于BUILD_64的方式进行处理)

The code functions the same as its non-buffered padded counterpart above. Note how p returns the beginning position within the buffer where sz number of bits begins. Also note that you will need a constant for BITS_PER_LONG denoting the number of bits in a long on your hardware. (which is normally handled in a manner similar to BUILD_64)

注意:请注意,对static声明的一个限制是转换函数只能在任何一个printf调用中(或在任何一行代码中)使用一次,因为二进制转换只有一个存储阵列. (您始终可以拨打任意数量的电话,并将结果存储在拨打printf电话之前的不同位置)

note: just be aware that one limitation to a static declaration is the conversion function can only be used once in any one printf call (or within any single line of code) since there is only one storage array for the binary conversion. (You can always make any number of calls and store the results in different locations just before the making the printf call)

二进制打印的最后一个变化是打印带有分隔符的表示形式,以使其更易于识别和比较二进制字符串(尤其是在处理较长的01'seg序列时:/p>

One final variation on the binary print is the print the representation with separators included to make it easier to identify and compare between binary strings (especially when dealing with longer sequences of 0's and 1's. e.g.:

hexval : 0xdeadbeef  =>  11011110-10101101-10111110-11101111

该函数的工作原理与上面的binpad相同,除了静态缓冲区更大以容纳分隔符外,还对位位置进行了额外的检查,以确定何时应将分隔符添加到缓冲区中:/p>

The function essentially works the same as binpad above, but with the addition that the static buffer is larger to accommodate the separators and an additional check on bit-position to determine when a separator should be added to the buffer:

/** 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位的校验,等等.您可以处理带有getops的参数或少数简单选项的参数,您可以简单地使用循环.在Linux上,代码应响应的唯一必需参数是-h以获得帮助,而-v则获得版本.虽然没有人为简短示例等进行此操作,但是拥有该信息至少是一件好事.查看下面的示例,该示例将所有内容组合在一起,如果您有任何疑问,请告诉我:

The remainder of your problem is simply to process the command line arguments, and perform the conversion from input string to unsigned value along with the validation checks that the number does not exceed 32-bits, etc.. You can either process the arguments with getops or for a small number of simple options you can simply use a loop. On Linux, the only required arguments your code should respond to are -h for help and -v for version. While nobody does this for short examples, etc., it is at least nice to have that information. Look over the following example that puts all the pieces together and let me know if you have any questions:

#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将十六进制转换为二进制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆