首页 文章

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

提问于
浏览
1

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

输出:0000 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;
    }

4 回答

  • 0

    有许多方法可以为任何数字打印二进制表示 . 首先,你可以直接输出你的移位和索引操作的结果(到 stdout ,一个文件等...)这似乎是你开始的方法,但后来你声明了一个32位缓冲区 . 虽然您当然可以这样做,但如果您不打算返回指向已完成缓冲区的指针,则无需缓冲结果 . (这让我想到了我的第3点,下面)

    简单地输出比特而不存储/返回指向以空字符串终止的字符串中的比特的指针,它具有其位置,但通常使用有限 . 然而,这是一个包含所有方法基础的常见问题 . 可以按如下方式创建未填充的二进制表示:

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

    评论相当明确 . 该方案是将每个位从最高有效位开始移位(例如,位31(31-0)为32位数 . 检查移位后是否有任何1位(如果不是,则移位超过最大位)数字中的有效位位置,无需打印) . 一旦在 rem 中找到一个位,在循环迭代的其余部分中始终会有位位打印,因为您正在减少量 . 最重要的位(首先打印),最终会以正确的顺序打印出您的位,并且只打印构成该位数的位数 .

    通常,当您只是将二进制表示直接输出到屏幕时,您只需要输出最高位的位 . (这可以防止输出一个 1 ,其前面有63 0 的东西 . )

    接下来,将填充的二进制表示输出到某个位数 . 如果您只想查看任何数字中较低的 8, 16, 32, ... 位,但希望每次都有一个固定位数的表示,这非常有用 . 在这里,您只需传递您想要查看的位数 . 然后,您的函数将循环遍历数字中的位数并输出结果:

    /** 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'

    现在为上面提到的第三点 . 从代码主体中的格式化角度来看,简单地输出位是很麻烦的 . 我发现将这些位存储在一个字符数组中是非常有用的(nul-terminated所以它可以被视为一个字符串)并返回一个指向数组的指针,因此它可以传递给 printf 等 . 现在你要么必须通过一个足够大小的数组作为参数,声明一个 static 数组,以便在函数返回时不销毁该数组,或者为该函数内的数组动态分配存储 . 根据代码的需要,你必须权衡所有的优点和缺点 . 例如 . :

    /** 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 的方式处理)

    note: 只要知道 static 声明的一个限制是转换函数只能在任何一个 printf 调用中使用一次(或在任何一行代码中使用),因为二进制转换只有一个存储阵列 . (您可以随时拨打任意号码并将结果存储在拨打 printf 之前的不同位置)

    二进制打印的最后一个变体是打印包含分隔符的表示,以便更容易识别和比较二进制字符串(特别是在处理 0 和_712924的较长序列时 . 例如:

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

    该函数基本上与上面的 binpad 相同,但添加了静态缓冲区以容纳分隔符,并额外检查位位置以确定何时应将分隔符添加到缓冲区:

    /** 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 表示版本 . 虽然没有人为简短的例子等做这件事,但获得这些信息至少是好的 . 查看以下将所有部分放在一起的示例,如果您有任何疑问,请告诉我:

    #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);
    }
    

    Use/Output

    $ ./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
    
  • 0

    每个棕色都作为一系列位存储在机器中 . 要将它们打印到控制台,您需要传递一个字符串,其中每个字符为1(0x31)或0(0x30),具体取决于是否设置了相应的数字位 . 最后一个字符必须是'\ 0'才能表示字符串的结尾 .

    在准备好字符缓冲区后,可以使用例如将它们打印到控制台 . fprintf

    fprintf(stdout, "%s\n", binaryNumber); // (maybe use stderr)
    

    稍微纠正你的代码,以确保字符串是NULL终止(它有'\ 0'作为缓冲区中的最后一个字符),你把字符放入缓冲区(否则1和0不是可打印的字符放入缓冲区,你会看到完全没有输出):

    void
    hex_to_bin_print(unsigned long number)
    {
        char binaryNumber[33];
        int i;
        for (i = 31; i >= 0; --i)
        {
            binaryNumber[i] = (number & 1) ? '1' : '0';
            number >>= 1;
        }
        binaryNumber[32] = '\0';
        fprintf(stdout, "Number %s\n", binaryNumber);
    }
    
    int main(void) {
        hex_to_bin_print(1);
        hex_to_bin_print(2);
        hex_to_bin_print(15);
        hex_to_bin_print(127);
        hex_to_bin_print(256);
        hex_to_bin_print(12345);
        return 0;
    }
    

    打印:

    编号00000000000000000000000000000001

    编号00000000000000000000000000000010

    编号00000000000000000000000000001111

    编号00000000000000000000000001111111

    编号00000000000000000000000100000000

    编号00000000000000000011000000111001

  • 1

    首先,将从命令行获取的字符串转换为整数,最简单的方法是使用sscanf

    例如

    if ( sscanf( argv[1], "%X", &n ) == 1)
    {
      ...
    

    现在你有十进制值 n .

    要转换为二进制,您需要遍历无符号整数中的每个位 .

    通过按位和小数值,您可以检查每个位是否已设置并打印“1”或“0”,具体取决于位

    for (int i = 0; i < 32; ++i)
    {
       unsigned int mask = 0x8000 >> i; // this bit we check
       char ch = (n & mask) ? '1' : '0'; // see if it is set or not
       ...
    }
    
  • 0

    这里's one way your program could look. I' ve评论了重要的部分,但是你必须查看正在使用的函数的文档 . 如果您正在使用linux(看起来您正在判断原始问题)那么您可以使用linux "manual pages"(例如 man sscanf )来提供有关sscanf或C库中任何其他函数的完整信息 .

    编译它: gcc main.c -o lab3

    /* main.c */
    #include <stdio.h> //provides putchar()
    #include <strings.h> //provides sscanf() and strcmp()
    #include <stdlib.h> //provides EXIT_x values
    
    void printBits(unsigned long i)
    {
      int j; //define a loop counter
    
      for(j = 0 ; j < 32 ; j++)
      {
        //test the highest bit and write a 1 or a 0
        //(we always test the highest bit but we shift the number along each time)
        putchar(i & 0x80000000 ? '1' : '0');
    
        //shift the bits along by one ready for the next loop iteration
        i <<= 1;
    
        //print a space after every 4th bit to break it up into nybbles
        if((j % 4) == 3)
          putchar(' ');
      }
    
      //finish the output in a tidy manner by writin a newline
      putchar('\n');
    }
    
    
    //a helpful function to assist the user
    void usage(const char* progname)
    {
      //show the user the proper way to run the program
      printf("%s -p 0x1234abcd\n", progname);
    }
    
    //this version of the main() signature gives access to commandline arguments
    int main(int argc, char** argv)
    {
      //flag to show the commandline arguments are in the wrong format
      int badargs = 0;
    
      //variable to store the 32 bit number given by the user
      unsigned long value;
    
      if(argc == 3) //do we have the right number of commandline arguments?
        if(strcmp(argv[1], "-p") == 0) //is argv[1] equal to "-p" ?
          if(sscanf(argv[2], "0x%x", &value) == 1) //is the number formatted like hex?
            printBits(value); //success, user input was good, print the bits!
          else
            badargs = 1; //the integer was not properly formatted as hexadecimal like 0x1234
        else
          badargs = 1; //argv[1] was not "-p"
      else
        badargs = 1; //wrong number of args given by user
    
      if(badargs) //we detected bad argument syntax earlier so we'd better remind the user what to do
      {
        printf("Incorrect argument syntax\n\n\t");
        usage(argv[0]); //argv[0] is the name of your executable program file ("lab3" in your case)
        putchar('\n');
        return EXIT_FAILURE;
      }
    
      return EXIT_SUCCESS;
    }
    

    我自己写了这个,但网上有很多这种“教学练习”的例子,所以我认为在这里只包括逐字代码并不是一个扰流 .

相关问题