数字转二进制(4种方法) | 位域(位段)应用 —— 从内存中提取数字的二进制

有关位段的知识点,可以参考文章:有关联合体嵌套结构体 、位域(位段)、小端存放


一、对于将求解整数的二进制的几种思路

对于数字转二进制的求解方法有很多:

1. 利用二进制满2进1的特性反向操作,对数字取余,整除2 。
#include<stdio.h>

int main(void)
{
        char str[65] = "";
        unsigned long long n;

        printf("Supports a maximum of 64 bits \ninput:");
        scanf("%lld",&n);

        int i = 0;
        while (n > 0)
        {
                str[i++] = n%2;  // 保存余数
                n /= 2;         // 整除操作
        }

        printf("This number of binary is:\n");

        while (i > 0)
        {
                printf("%d",str[--i]);
        }
        printf("\n");

        return 0;
}

在这里插入图片描述

2. 利用位运算,判断整数n的每一位上是否存在1
#include<stdio.h>

// 利用二进制运算输出
void show_bit(unsigned long long num)
{
        unsigned long long i = (1LLU<<63);
        printf("The binary of this number is: \n");
        while(i > 0)
        {
                printf("%d", (num&i) == i );	// 判断当前位上是否是 1
                if( (i&0x0101010101010101) == i ) printf(" ");	// 每8位之间一个空格
                i >>= 1;
        }
        printf("\n\n");
}


int main(void)
{
        unsigned long long n;

        printf("Supports a maximum of 64 bits \ninput:");
        scanf("%lld",&n);

        show_bit(n);

        return 0;
}

在这里插入图片描述

3. 利用C++库函数 bitset 实现整数转二进制字符串
#include <iostream>
#include <bitset>

using std::bitset;	// 类声明

// 求num最少需要几个字节存储
int get_bytes(unsigned long long num)
{
        int len = 0;
        while(num > 0)
        {
                num >>= 8;
                len += 1;
        }
        //if(len == 3) len = 4; // 3,4字节都以4字节输出(int类型)
        //if(len > 4)  len = 8; // 大于4字节都以8字节输出
        return len;
}

int main()
{
        unsigned long long num;

        std::cout << "Supports a maximum of 64 bits\n";
        std::cin >> num;

        const unsigned int n = get_bytes(num);
        std::cout << "The binary of this number is:\t"
                << "-- " << n << "bytes. \n";

        if( n == 1) { // 1字节
                std::cout <<  bitset<8>(num).to_string() << std::endl;
        }
        else if(n == 2) { // 2字节
                std::cout <<  bitset<16>(num).to_string() << std::endl;
        }
        else if(n <= 4) { // 4字节
                std::cout <<  bitset<32>(num).to_string() << std::endl;
        }
        else if(n <= 8) { // 8字节
                std::cout <<  bitset<64>(num).to_string() << std::endl;
        }

        return 0;
}

在这里插入图片描述

4. 利用结构体位域,将整数内存中的二进制数拿到
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>


#define BIT_T_SIZE  0x01 // 1字节
#define BIT_8_SIZE  0x01 // 1字节
#define BIT_16_SIZE 0x02 // 2字节
#define BIT_32_SIZE 0x04 // 4字节
#define BIT_64_SIZE 0x08 // 8字节


// 定义bit结构
typedef struct Bit_t
{
        unsigned char bit1 : 1;
        unsigned char bit2 : 1;
        unsigned char bit3 : 1;
        unsigned char bit4 : 1;
        unsigned char bit5 : 1;
        unsigned char bit6 : 1;
        unsigned char bit7 : 1;
        unsigned char bit8 : 1;
}Bit_t;

// 定义8字节64位数据结构
typedef union Bit_64
{
        unsigned long long bytes;
        Bit_t bits[8];
}Bit_64, *Bit;  // 指针形式为 Bit


// 判断大小端
int is_big_end()
{
        unsigned short x = 0x0001;
        unsigned char *p = (unsigned char*)&x;
        unsigned char big_end = 1;      // 默认大端存储
        if( (*p) == 0x01)
        {
                big_end = 0;    // 小端存储
        }
        return (int)big_end;
}

// 输出二进制
static void show_bitstring(Bit bt, int n)
{
        if(n <= 0 || n > 8)     // 输出n个字节
        {
                perror("show_bitstring: <n> value is error, n->{1,2,3,4}\n");
                return ;
        }

        printf("%d bytes display:\n", n);
        int op = (is_big_end() == 1) ? 1 : -1;
        int i = (is_big_end() == 1) ? 0 : n-1;  // 大端存储,存储次序与人类直观于都相同
        while(i >= 0 && i < n)
        {
                if(is_big_end() == 1) {
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit1,
                                bt->bits[i].bit2,   bt->bits[i].bit3,
                                bt->bits[i].bit4,   bt->bits[i].bit5,
                                bt->bits[i].bit6,   bt->bits[i].bit7,
                                bt->bits[i].bit8);
                }
                else {  // 小端,与人类直观感受相反的存储方式
                        // bits[4]{b8,b7,b6...b1}, bits[3]{..}, bits[2]{...}, bits[1]{...}
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit8,
                                bt->bits[i].bit7,   bt->bits[i].bit6,
                                bt->bits[i].bit5,   bt->bits[i].bit4,
                                bt->bits[i].bit3,   bt->bits[i].bit2,
                                bt->bits[i].bit1);
                }

                i += op;
        }
        printf("\n");

}

// 获得输入整数存储所需的最少字节数
static int get_minBytes(unsigned long long u)
{
        int cnt = 0;
        while (u != 0)
        {
                u >>= 8;
                cnt ++;
        }
        return cnt;
}


// 利用二进制运算输出
void show_bit(unsigned long long num)
{
        unsigned long long i = (1LLU<<63);
        printf("The binary of this number is: \n");
        while(i > 0)
        {
                printf("%d", (num&i) == i );
                if( (i&0x0101010101010101) == i ) printf(" ");
                i >>= 1;
        }
        printf("\n\n");
}



int main(int argc, char *argv[])
{
        printf("Supports a maximum of 64 bits\n"
                "input: ");     // 输入提示

        unsigned long long a;
        scanf("%lli", &a);      // 输入,%i可以根据前缀区分8进制、10进制、16进制

        show_bit((unsigned long long)a);        // 对照组,参考输出是否正确

        Bit_64 b64 = {.bytes = a}; // 将输入整数转换成可以解析内部二进制的数据类型
        switch(get_minBytes(a))
        {
        case 1: // 最少需要1字节
                show_bitstring((Bit)&b64, BIT_8_SIZE);  // 建议使用宏
        case 2: // 2字节
                show_bitstring((Bit)&b64, BIT_16_SIZE); // 建议使用宏
        case 3: case 4: // 4字节
                show_bitstring((Bit)&b64, BIT_32_SIZE); // 建议使用宏
        case 5: case 6: case 7: case 8: // 8字节
                show_bitstring((Bit)&b64, BIT_64_SIZE); // 建议使用宏
        break;
        default: break;
        }

        return 0;
}

在这里插入图片描述

二、设计并实现命令行参数版本

关于getopt函数,请参考文章:命令行参数解析函数 getopt、getopt_long

对于前几个版本的整数转二进制太过简单,这里就不再实现了。这里只将最后一个程序实现成带有命令行参数的版本。

其中涉及到的知识有:

  • 联合体与结构体共用
  • 结构体位段的使用
  • 大小端存储方式
  • getopt 函数的使用
  • fcanf 函数的使用
1. 首先是数据结构的定义

对于C语言中常见的类型主要有四种:

  • 1字节:char
  • 2字节:short
  • 4字节:int(long int)、float
  • 8字节:long long(long long int)、double
    注:有些机器上 long 表示8字节。

联合体可以让内部变量共同占用同一内存空间,而结构体拥有位段这种限制内部成员占用比特位数的机制,两者结合我们便可以得到一个变量在内存中存储的01比特串。参考下图:
在这里插入图片描述
对于上述数据结构,我们将 .bytes赋值为 255, 它的内存中应当存放这8个比特1.
在这里插入图片描述
而结构体 .bits 与 .bytes 同用一片内存空间,也就是说此时结构体 .bits内部的 bit1~bit8 刚好可以表示 .bytes内部每一位的比特值。

同理,我们按照2字节变量、4字节变量分别在定义出两种对应的数据结构。

数据结构定义参考如下代码:

// 定义宏,规定每个结构可以存储的字节大小
#define BIT_T_SIZE  0x01 // 1字节
#define BIT_8_SIZE  0x01 // 1字节
#define BIT_16_SIZE 0x02 // 2字节
#define BIT_32_SIZE 0x04 // 4字节
#define BIT_64_SIZE 0x08 // 8字节


// 定义bit结构
typedef struct Bit_t
{
        unsigned char bit1 : 1;
        unsigned char bit2 : 1;
        unsigned char bit3 : 1;
        unsigned char bit4 : 1;
        unsigned char bit5 : 1;
        unsigned char bit6 : 1;
        unsigned char bit7 : 1;
        unsigned char bit8 : 1;
}Bit_t;

// 定义一字节8位数据结构
typedef union Bit_8
{
        unsigned char bytes;
        Bit_t bits[1];
}Bit_8;

// 定义二字节16位数据结构
typedef union Bit_16
{
        unsigned short bytes;
        Bit_t bits[2];
}Bit_16;

// 定义四字节32位数据结构
typedef union Bit_32
{
        unsigned int bytes;
        //Bit_8 bits[4];
        Bit_t bits[4];
}Bit_32;

// 定义8字节64位数据结构
typedef union Bit_64
{
        unsigned long long bytes;
        Bit_t bits[8];
}Bit_64, *Bit;  // 指针形式为 Bit


2. 数据的表示,大端?小端?

上面提到可以用结构体 .bits内部的 bit1~bit8 表示 .bytes内部每一位的比特值。

那么究竟 bits::bit1 应该对应 .bytes二进制中的低位呢,还是高位呢?这就需要判断判断一下该计算机的数据存储方式了。

关于小端存储,这里截取二张图。原文章链接:浮点数问题详解,printf(“%d\n“, 8.0); 为什么输出 0 ?——小端存储 & 浮点数格式 & 格式化输出 | bitset的使用 与 二进制原码分析
在这里插入图片描述
数据的存储:
在这里插入图片描述
对于小端的存储是以交错的形式存储在内存中的。如果计算是以小端存储的,那么 .bytes 与 .bits 的对应关系为: .bytes => .bits{bit8,bit7,bit5…bit1}。

同理,如果是大端存储,那么对应关系应为:.bytes => .bits{bit1,bit2,bit3…bit8}。

而对于多字节的数据结构 Bit_16、Bit_32、Bit_64 而言,也是相同的道理,它们的对应关系为:以 Bit_32 为例

  • 小端: .bytes => bits[4]{bit8,…bit1}, bit[3]{bit8…bit1}, bit[2]{bit8…bit1}, bit[1]{bit8…bit1}
  • 大端: .bytes => bits[1]{bit1,…bit8}, bit[2]{bit1…bit8}, bit[3]{bit1…bit8}, bit[4]{bit1…bit8}

对应代码:

判断大小端: 返回当前主机序是否为大端序

// 判断大小端
int is_big_end()
{
        unsigned short x = 0x0001;
        unsigned char *p = (unsigned char*)&x;
        unsigned char big_end = 1;      // 默认大端存储
        if( (*p) == 0x01)
        {
                big_end = 0;    // 小端存储
        }
        return (int)big_end;
}

输出二进制

  • 如果是小端,从bits[0] -> bits[1] 输出,且对于每一个 .bits[i] 而言,输出顺序为 bit1,bit2…bit8
  • 如果是小端,从bits[n] -> bits[0] 输出,且对于每一个 .bits[i] 而言,输出顺序为 bit8,bit7…bit1

代码:

// 输出二进制
static void show_bitstring(Bit bt, int n)
{
        if(n <= 0 || n > 8)     // 输出n个字节
        {
                perror("show_bitstring: <n> value is error, n->{1,2,3,4}\n");
                return ;
        }

        printf("%d bytes display:\n", n);
        int op = (is_big_end() == 1) ? 1 : -1;
        int i = (is_big_end() == 1) ? 0 : n-1;  // 大端存储,存储次序与人类直观于都相同
        while(i >= 0 && i < n)
        {
                if(is_big_end() == 1) {
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit1,
                                bt->bits[i].bit2,   bt->bits[i].bit3,
                                bt->bits[i].bit4,   bt->bits[i].bit5,
                                bt->bits[i].bit6,   bt->bits[i].bit7,
                                bt->bits[i].bit8);
                }
                else {  // 小端,与人类直观感受相反的存储方式
                        // bits[4]{b8,b7,b6...b1}, bits[3]{..}, bits[2]{...}, bits[1]{...}
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit8,
                                bt->bits[i].bit7,   bt->bits[i].bit6,
                                bt->bits[i].bit5,   bt->bits[i].bit4,
                                bt->bits[i].bit3,   bt->bits[i].bit2,
                                bt->bits[i].bit1);
                }

                i += op;
        }
        printf("\n");

}

3. 数据的输入方式,比特串?8进制?10进制?16进制?

对于数据的输入,我们也需要额外进行处理。

使用 scanf("%i") 的方式虽然可以自动识别输入数字的进制,但是需要前缀作为补充。并且这种方式是不支持比特串的方式输入的,因此我们需要设计一套独立的输入系统。

对于8进制、10进制、16进制而言我们可以采用他们独有的输入辨识符 %o%d%x。 这样哪怕我们不加前缀程序也可以正确识别。

对于比特串的输入,我们需要特殊的设计,这里同样需要考虑大小端的问题。

Bit_t 结构赋值函数
在我们的数据结构的设计中,最小的数据结构为 Bit_t 结构,同时它内部可以拆分到每一位比特,因此我们需要一个能够给 Bit_t 结构赋值的函数。

它的实现非常简单,将传入的比特串截取8位,赋值到给定的Bit_t中即可。
代码参考:

// 将8个表示二进制的字符转为二进制
static void char2bit(const char in[], int start, Bit bt, int i)
{
        char bstr[9] = "0";	// 使用bstr保存,因为in[start]可能存在剩余输入不足的问题,例如输入了 “0101”
        strncpy(bstr, &in[start], 8); // 拷贝8个
        if(is_big_end() == 1) {
                 bt->bits[i].bit1 = bstr[0];
                 bt->bits[i].bit2 = bstr[1];
                 bt->bits[i].bit3 = bstr[2];
                 bt->bits[i].bit4 = bstr[3];
                 bt->bits[i].bit5 = bstr[4];
                 bt->bits[i].bit6 = bstr[5];
                 bt->bits[i].bit7 = bstr[6];
                 bt->bits[i].bit8 = bstr[7];
        }
        else {  // 小端,与人类直观感受相反的存储方式
                 bt->bits[i].bit1 = bstr[7];
                 bt->bits[i].bit2 = bstr[6];
                 bt->bits[i].bit3 = bstr[5];
                 bt->bits[i].bit4 = bstr[4];
                 bt->bits[i].bit5 = bstr[3];
                 bt->bits[i].bit6 = bstr[2];
                 bt->bits[i].bit7 = bstr[1];
                 bt->bits[i].bit8 = bstr[0];
        }
}

.bits 数组赋值函数
对于.bits[] 数组,我们按照主机序遍历数组即可。大端:则bits[0]->bits[n],小端:则bits[n]->bits[0]。
而对于每个 .bits[i] 内部的操作,我们交给 char2bit() 函数去做即可。

这里将输入的比特字符串,按字节分割的时候有两种方式,一种逆序分割,正序存放到数组。另一种是正序分割,逆序存放到数组。

  • 逆序分割字符串,数组正序遍历。
    在这里插入图片描述
  • 正序分割字符串,数组反向遍历接收
    在这里插入图片描述

下面代码采用第二种方式,即正序的以字节长度分割比特串。根据主机字节序不同考虑数组的遍历方向。
代码参考:

// 使用二进制输入
static unsigned long long input_bin(const char* buff)
{

        Bit_64 bt_num = {.bytes = 0};
        int len = strlen(buff);
        printf("input bin. length = %d\n", len);
        int bytes = (len + 7) / 8;
        int i = 0; 	// 遍历比特串
        int t = (is_big_end() == 1) ? 0 : bytes - 1;	// 遍历数组,方向有主机字节序确定
        int op = (is_big_end() == 1) ? 1 : -1;
        while(0 <= t && t < bytes)
        {
                char2bit(buff, i, &bt_num, t); // 大端or小端,字符转bit
                i += 8;
                t += (op * 1);
        }
        return bt_num.bytes;
}

4. 命令参数的设计 与 输出的格式

对于命令行参数,我们需要用到 getopt 函数。 关于getopt函数请参考:命令行参数解析函数 getopt、getopt_long

处理输入

首先我们的程序很简单,只要求将输入的数转换成二进制表示出来即可。同时我们需要接受一个以 - 开头的参数,指定输入数据的类型,那么我们的程序至多接受三个参数。

 // 处理参数
 if(argc <= 1 || argc > 3){
         printf ("Supports a maximum of 64 bits\n"
                 "Format:  ./program <opt> [value]\n"
                 "Example: ./program -d 1234567\n"
                 "\n可选参数:\n"
                 "\t-h : 十六进制输入\n"
                 "\t-d : 八进制输入\n"
                 "\t-d : 十进制输入\n"
                 "\t-b : 二进制输入\n");
         return 0;
 }

其次,对于4中不同的输入方式,我们需要设置对应的处理方案:

 int opt;
 char* scale = "%lld";
 char* buff = NULL;
 while( (opt = getopt(argc, argv, "h:o:d:b:")) != -1 )
 {
         switch(opt)
         {
         case 'h':
                 scale = "%llx";
                 buff = optarg;
                 break;
         case 'o':
                 scale = "%llo";
                 buff = optarg;
                 break;
         case 'd':
                 scale = "%lld";
                 buff = optarg;
                 break;
         case 'b':
                 scale = NULL;
                 buff = optarg;
                 break;
         case '?':	// 参数出错,直接退出程序
                 return 1;
         default:
                 abort ();
         }
 }

使用 scale 保存不同进制输出的格式,buff 中存放输入的数据,最后统一使用 sscanf(buff, scale, &a); 读到变量a中。

而对于二进制的输入,无需 scale 的格式,这里需要调用前面实现的 input_bin() 函数。

处理逻辑如下:

 if(scale == NULL)
 {
         a = input_bin(buff);
 }
 else
 {
         sscanf(buff, scale, &a);
 }

处理输出

对于输出而言,我们提供了四种输出格式,即1字节、2字节、4字节、8字节的输出。同时为了判断输出是否准确,这里采用了对照组(采用位运算实现)输出。

 // 输出输入的数
 printf("input num: OCT=%llo \tDEC=%llu \tHEX=%#llX \n", a, a, a);
 // 输出二进制
 show_bit((unsigned long long)a);

 Bit_64 b64 = {.bytes = a}; // 将输入整数转换成可以解析内部二进制的数据类型
 switch(get_minBytes(a))
 {
 case 1: // 最少需要1字节
         show_bitstring((Bit)&b64, BIT_8_SIZE);  
 case 2: // 2字节
         show_bitstring((Bit)&b64, BIT_16_SIZE); 
 case 3: case 4: // 4字节
         show_bitstring((Bit)&b64, BIT_32_SIZE); 
 case 5: case 6: case 7: case 8: // 8字节
         show_bitstring((Bit)&b64, BIT_64_SIZE); 
 break;
 default: break;
 }

这里的处理逻辑是,输出大于等于该数据所需最小字节能表示的范围。


以上便是全部实现细节,代码使用C语言实现。如果我们使用C++面向对象的特性将会更容易实现。

附:完整代码——基于命令行实现的通过位段输出整数二进制程序
代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>


#define BIT_T_SIZE  0x01 // 1字节
#define BIT_8_SIZE  0x01 // 1字节
#define BIT_16_SIZE 0x02 // 2字节
#define BIT_32_SIZE 0x04 // 4字节
#define BIT_64_SIZE 0x08 // 8字节


// 定义bit结构
typedef struct Bit_t
{
        unsigned char bit1 : 1;
        unsigned char bit2 : 1;
        unsigned char bit3 : 1;
        unsigned char bit4 : 1;
        unsigned char bit5 : 1;
        unsigned char bit6 : 1;
        unsigned char bit7 : 1;
        unsigned char bit8 : 1;
}Bit_t;

// 定义一字节8位数据结构
typedef union Bit_8
{
        unsigned char bytes;
        Bit_t bits[1];
}Bit_8;

// 定义二字节16位数据结构
typedef union Bit_16
{
        unsigned short bytes;
        Bit_t bits[2];
}Bit_16;

// 定义四字节32位数据结构
typedef union Bit_32
{
        unsigned int bytes;
        Bit_t bits[4];
}Bit_32;

// 定义8字节16位数据结构
typedef union Bit_64
{
        unsigned long long bytes;
        Bit_t bits[8];
}Bit_64, *Bit;  // 指针形式为 Bit


// 判断大小端
int is_big_end()
{
        unsigned short x = 0x0001;
        unsigned char *p = (unsigned char*)&x;
        unsigned char big_end = 1;      // 默认大端存储
        if( (*p) == 0x01)
        {
                big_end = 0;    // 小端存储
        }
        return (int)big_end;
}

// 输出二进制
static void show_bitstring(Bit bt, int n)
{
        if(n <= 0 || n > 8)     // 输出n个字节
        {
                perror("show_bitstring: <n> value is error, n->{1,2,3,4}\n");
                return ;
        }

        printf("%d bytes display:\n", n);
        int op = (is_big_end() == 1) ? 1 : -1;
        int i = (is_big_end() == 1) ? 0 : n-1;  // 大端存储,存储次序与人类直观于都相同
        while(i >= 0 && i < n)
        {
                if(is_big_end() == 1) {
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit1,
                                bt->bits[i].bit2,   bt->bits[i].bit3,
                                bt->bits[i].bit4,   bt->bits[i].bit5,
                                bt->bits[i].bit6,   bt->bits[i].bit7,
                                bt->bits[i].bit8);
                }
                else {  // 小端,与人类直观感受相反的存储方式
                        // bits[4]{b8,b7,b6...b1}, bits[3]{..}, bits[2]{...}, bits[1]{...}
                        printf("%d%d%d%d%d%d%d%d ", bt->bits[i].bit8,
                                bt->bits[i].bit7,   bt->bits[i].bit6,
                                bt->bits[i].bit5,   bt->bits[i].bit4,
                                bt->bits[i].bit3,   bt->bits[i].bit2,
                                bt->bits[i].bit1);
                }

                i += op;
        }
        printf("\n");

}

// 获得输入整数存储所需的最少字节数
static int get_minBytes(unsigned long long u)
{
        int cnt = 0;
        while (u != 0)
        {
                u >>= 8;
                cnt ++;
        }
        return cnt;
}


// 将8个表示二进制的字符转为二进制
static void char2bit(const char in[], int start, Bit bt, int i)
{
        char bstr[9] = "0";
        strncpy(bstr, &in[start], 8); // 拷贝8个
        if(is_big_end() == 1) {
                 bt->bits[i].bit1 = bstr[0];
                 bt->bits[i].bit2 = bstr[1];
                 bt->bits[i].bit3 = bstr[2];
                 bt->bits[i].bit4 = bstr[3];
                 bt->bits[i].bit5 = bstr[4];
                 bt->bits[i].bit6 = bstr[5];
                 bt->bits[i].bit7 = bstr[6];
                 bt->bits[i].bit8 = bstr[7];
        }
        else {  // 小端,与人类直观感受相反的存储方式
                 bt->bits[i].bit1 = bstr[7];
                 bt->bits[i].bit2 = bstr[6];
                 bt->bits[i].bit3 = bstr[5];
                 bt->bits[i].bit4 = bstr[4];
                 bt->bits[i].bit5 = bstr[3];
                 bt->bits[i].bit6 = bstr[2];
                 bt->bits[i].bit7 = bstr[1];
                 bt->bits[i].bit8 = bstr[0];
        }
}
// 使用二进制输入
static unsigned long long input_bin(const char* buff)
{

        Bit_64 bt_num = {.bytes = 0};
        int len = strlen(buff);
        printf("input bin. length = %d\n", len);
        int bytes = (len + 7) / 8;
        int t = (is_big_end() == 1) ? 0 : bytes - 1;
        //int i = (is_big_end() == 1) ? 0 : (bytes-1) * 8; 
        int i = 0;	
        /* 如果字符串逆字节录入,则数组需要正序遍历
           如果数组逆序遍历,则字符串需要按正序字节遍历
        */
        int op = (is_big_end() == 1) ? 1 : -1;
        while(0 <= t && t < bytes)
        {
                char2bit(buff, i, &bt_num, t); // 大端or小端,字符转bit
                //i += (op * 8);	// ..
                i += 8;
                t += (op * 1);
        }
        return bt_num.bytes;
}

// 利用二进制运算输出
void show_bit(unsigned long long num)
{
        unsigned long long i = (1LLU<<63);
        printf("The binary of this number is: \n");
        while(i > 0)
        {
                printf("%d", (num&i) == i );
                if( (i&0x0101010101010101) == i ) printf(" ");
                i >>= 1;
        }
        printf("\n\n");
}



int main(int argc, char *argv[])
{
        // 处理参数
        if(argc <= 1 || argc > 3){
                printf ("Supports a maximum of 64 bits\n"
                        "Format:  ./program <opt> [value]\n"
                        "Example: ./program -d 1234567\n"
                        "\n可选参数:\n"
                        "\t-h : 十六进制输入\n"
                        "\t-d : 八进制输入\n"
                        "\t-d : 十进制输入\n"
                        "\t-b : 二进制输入\n");
                return 0;
        }

        unsigned long long a = 0LLU;

        int opt;
        char* scale = "%lld";
        char* buff = NULL;
        while( (opt = getopt(argc, argv, "h:o:d:b:")) != -1 )
        {
                switch(opt)
                {
                case 'h':
                        scale = "%llx";
                        buff = optarg;
                        break;
                case 'o':
                        scale = "%llo";
                        buff = optarg;
                        break;
                case 'd':
                        scale = "%lld";
                        buff = optarg;
                        //fscanf(optarg, "%lli", &a); // %i 同时接受 8、10、16进制,但需要前缀作区分
                        break;
                case 'b':
                        scale = NULL;
                        buff = optarg;
                        break;
                case '?':
                        /*
                        if (optopt == 'h' || optopt == 'o' || optopt == 'd' || optopt == 'b')
                                fprintf (stderr, "Option -%c requires an argument.\n", optopt);
                        else if (isprint (optopt))      // 检测一个字符是否是可打印字符
                                fprintf (stderr, "Unknown option `-%c'.\n", optopt);
                        else                                            // 如果不可打印,输出其ascii值
                                fprintf (stderr,
                                        "Unknown option character `\\x%x'.\n",
                                        optopt);
                        */
                        return 1;
                default:
                        abort ();
                }
        }

        if(scale == NULL)
        {
                a = input_bin(buff);
        }
        else
        {
                sscanf(buff, scale, &a);
        }

        // 输出输入的数
        printf("input num: OCT=%llo \tDEC=%llu \tHEX=%#llX \n", a, a, a);
        // 输出二进制
        show_bit((unsigned long long)a);

        Bit_64 b64 = {.bytes = a}; // 将输入整数转换成可以解析内部二进制的数据类型
        switch(get_minBytes(a))
        {
        case 1: // 最少需要1字节
                //Bit_8 b8 = {.bytes = a};
                //show_bitstring((Bit)&b8, sizeof(b8.bytes));
                show_bitstring((Bit)&b64, BIT_8_SIZE);  // 建议使用宏

                // 不是用宏也可以使用 sizeof() 计算结构体中 bytes 是几个字节,需要注意的
                //show_bitstring((Bit)&b64, sizeof(((Bit_8*)(0))->bytes) ); // c中不可以直接测量没有定义的实例的结构体成员大小
        case 2: // 2字节
                //Bit_16 b16 = {.bytes = a};
                //show_bitstring((Bit)&b16, sizeof(b16.bytes));
                show_bitstring((Bit)&b64, BIT_16_SIZE); // 建议使用宏
        case 3: case 4: // 4字节
                //Bit_32 b32 = {.bytes = a};
                //show_bitstring((Bit)&b32, sizeof(b32.bytes));
                show_bitstring((Bit)&b64, BIT_32_SIZE); // 建议使用宏
        case 5: case 6: case 7: case 8: // 8字节
                //Bit_64 b64 = {.bytes = a};
                //show_bitstring((Bit)&b64, sizeof(b64.bytes));
                show_bitstring((Bit)&b64, BIT_64_SIZE); // 建议使用宏
        break;
        default: break;
        }

        return 0;
}

演示:

编译:
在这里插入图片描述
2进制输入:
在这里插入图片描述
在这里插入图片描述
8进制输入:
在这里插入图片描述
在这里插入图片描述
10进制输入:
在这里插入图片描述
在这里插入图片描述
十六进制输入:
在这里插入图片描述
在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值