第十五章 位操作

  • 按位取反运算符:~,作用:将对应二进制码取反。代码示例example.c:

#include <stdio.h>

int main(void)
{
    unsigned char val = 2; // 00000010
    unsigned char new_val = ~val; // 11111101
    
    printf("Now val is %d\n", val);
    printf("Now new_val is %d\n", new_val);
    
    return 0; 
}

输出结果:

  • 按位与运算符:&,作用:两个二进制位都为真时取真。代码示例example.c :

#include <stdio.h>

int main(void)
{
    unsigned char var1 = 0x93; // 147 10010011
    unsigned char var2 = 0x3d; // 61  00111101
    
    unsigned char var3 = var1 & var2; //0x11 17 00010001
    printf("var1 is %d\n", var1);
    printf("var2 is %d\n", var2);
    printf("var3 is %d\n", var3);
    
    var1 &= var2; //Equal to var1 = var1 & var2;
    printf("Now var1 is %d\n", var1);
    
    return 0;
}

输出结果:

  • 按位或运算符:|,作用:当两个二进制位有一个为真时取真。代码示例example.c:

#include <stdio.h>

int main(void)
{
    unsigned char var1 = 0x93; // 10010011 147
    unsigned char var2 = 0x3d; // 00111101 61
    unsigned char var3 = var1 | var2; // 10111111 0xbf 191
    
    printf("var1 = %d\n", var1);
    printf("var2 = %d\n", var2);
    printf("var3 = %d\n", var3);
    
    var1 |= var2; // Equal to var1 = var1 | var2
    printf("Now var1 = %d\n", var1);
    
    return 0;
}

输出结果:

  • 按位异或运算符:^,作用:当且仅当两个二进制位中仅有一个为真时取真。代码示例example.c:

#include <stdio.h>

int main(void)
{
    unsigned char var1 = 0x93; // 10010011 147
    unsigned char var2 = 0x3d; // 00111101 61
    unsigned char var3 = var1 ^ var2; // 10101110 0xae 174
    
    printf("var1 = %d\n", var1);
    printf("var2 = %d\n", var2);
    printf("var3 = %d\n", var3);
    
    var1 ^= var2; // Equal to var1 = var1 ^ var2;
    printf("Now var1 = %d\n", var1);
    
    return 0;
}

输出结果:

  • 左移运算符:<<,作用:将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数,左侧运算对象移除左末端位的值丢失,用0填充空出的位置。示例代码:example.c

#include <stdio.h>

int main(void)
{
    int stonk = 1; // 00000001
    int onkoo;
    
    onkoo = stonk << 2; // 00000100
    stonk <<= 2;
    printf("onkoo = %d\n", onkoo);
    printf("stonk = %d\n", stonk);
    
    return 0;
}

输出结果:

  • 右移运算符:>>,作用:将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数,左侧运算对象移除右末端位的值丢失,对于有符号类型,取决于机器用0或者1填充空出的位置,对于无符号类型,都用0填充空出的位置。示例代码example.c:

#include <stdio.h>

int main(void)
{
    signed char var1 = 0x8a; // 10001010 -(256-138) = -118
    signed char var2 = var1 >> 2; // 11100010 -(256 - 0xe2) = -(256-226) = -30
    unsigned char var3 = 0x8a >> 2; // 00100010 0x22 34
    
    printf("var1 = %d\n", var1);
    printf("var2 = %d\n", var2);
    printf("var3 = %d\n", var3);
    
    return 0;
}

输出结果:

  • 程序清单15.1,binbit.c:

/*binbit.c -- 使用位操作显示二进制 */
#include <stdio.h>
#include <limits.h> //提供 CHAR_BIT 的定义,CHAR_BIT 表示每字节的位数 

char * itobs(int, char *);
void show_bstr(const char *);

int main(void)
{
    char bin_str[CHAR_BIT * sizeof(int) + 1];
    int number;
    
    puts("Enter integers and see them in binary.");
    puts("Non-numeric input terminates program.");
    while (scanf("%d", &number) == 1)
    {
        itobs(number, bin_str);
        printf("%d is ", number);
        show_bstr(bin_str);
        putchar('\n');
    }
    puts("Bye!");
    
    return 0;
}

char  * itobs(int n, char * ps)
{
    int i;
    static const int size = CHAR_BIT * sizeof(int);
    
    for (i = size - 1; i >= 0; i--, n >>=1) // 7 -> 0000 0111
        ps[i] = (01 & n) + '0'; // 0000 0001
    ps[size] = '\0';
    
    return ps;
}

void show_bstr(const char * str)
{
    int i = 0;
    
    while(str[i])
    {
        putchar(str[i]);
        if (++i % 4 == 0 && str[i])
            putchar(' ');
    }
}

输出结果:

  • 程序清单15.2, invert4.c:

/*invert4.c -- 使用位操作显示二进制 */
#include <stdio.h>
#include <limits.h> //提供 CHAR_BIT 的定义,CHAR_BIT 表示每字节的位数 

char * itobs(int, char *);
void show_bstr(const char *);
int invert_end(int num, int bits);

int main(void)
{
    char bin_str[CHAR_BIT * sizeof(int) + 1];
    int number;
    
    puts("Enter integers and see them in binary.");
    puts("Non-numeric input terminates program.");
    while (scanf("%d", &number) == 1)
    {
        itobs(number, bin_str);
        printf("%d is ", number);
        show_bstr(bin_str);
        putchar('\n');
        number = invert_end(number, 4);
        printf("Inverting the last 4 bits gives\n");
        show_bstr(itobs(number, bin_str));
        putchar('\n');
    }
    puts("Bye!");
    
    return 0;
}

char  * itobs(int n, char * ps)
{
    int i;
    static const int size = CHAR_BIT * sizeof(int);
    
    for (i = size - 1; i >= 0; i--, n >>= 1) // 7 -> 0000 0111
        ps[i] = (01 & n) + '0'; // 0000 0001
    ps[size] = '\0';
    
    return ps;
}

void show_bstr(const char * str)
{
    int i = 0;
    
    while(str[i])
    {
        putchar(str[i]);
        if (++i % 4 == 0 && str[i])
            putchar(' ');
    }
}

int invert_end(int num, int bits)
{
    int mask = 0;
    int bitval = 1;
    
    while (bits-- > 0)
    {
        mask |= bitval;
        bitval <<= 1;
    }
    
    return num ^ mask;
}

输出结果:

  • 程序清单15.3,fields.c:

/* fields.c -- 定义并使用字段 */
#include <stdio.h>
#include <stdbool.h>

/* 线的样式 */
#define SOLID 0
#define DOTTED 1
#define DASHED 2
/* 三原色 */
#define BLUE 4
#define GREEN 2
#define RED 1
/* 混合色 */
#define BLACK 0
#define YELLOW (RED | GREEN)
#define MAGENTA (RED | BLUE)
#define CYAN (GREEN | BLUE)
#define WHITE (RED | GREEN | BLUE)

const char * colors[8] = { "black", "red", "green", "yellow", 
"blue", "magenta", "cyan", "white" };

struct box_props {
    bool opaque               : 1;
    unsigned int fill_color   : 3;
    unsigned int              : 4;
    bool show_border          : 1;
    unsigned int border_color : 3;
    unsigned int border_style : 2;
    unsigned int              : 2;
}; 

void show_settings(const struct box_props * pb);

int main(void)
{
    /* 创建并使用 box_props 结构 */
    struct box_props box = { true, YELLOW, true, GREEN, DASHED };
    
    printf("Original box settings:\n");
    show_settings(&box);
    
    box.opaque = false;
    box.fill_color = WHITE;
    box.border_color = MAGENTA;
    box.border_style = SOLID;
    printf("\nModified box settings:\n");
    show_settings(&box);
    
    return 0;
}

void show_settings(const struct box_props * pb)
{
    printf("Box is %s.\n", pb->opaque == true ? "opaque" : "transparent");
    printf("The fill color is %s.\n", colors[pb->fill_color]);
    printf("Border %s.\n", pb->show_border == true ? "shown" : " not shown");
    printf("The border color is %s.\n", colors[pb->border_color]);
    printf("The border style is ");
    switch (pb->border_style)
    {
        case SOLID: printf("solid.\n"); break;
        case DOTTED: printf("dotted.\n"); break;
        case DASHED: printf("dashed.\n"); break;
        default:     printf("unknown type.\n");
    }
}

输出结果:

  • 程序清单15.4, dualview.c:

/* dualview.c -- 位字段和按位运算符 */
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
/* 位字段符号常量 */
/* 边框线样式 */
#define SOLID 0
#define DOTTED 1
#define DASHED 2
/* 三原色 */
#define BLUE 4
#define GREEN 2
#define RED 1
/* 混合色 */
#define BLACK 0
#define YELLOW (RED | GREEN)
#define MAGENTA (RED | BLUE)
#define CYAN (GREEN | BLUE)
#define WHITE (RED | GREEN | BLUE)

/* 按位方法用到的符号常量 */
#define OPAQUE 0x1
#define FILL_BLUE 0x8
#define FILL_GREEN 0x4
#define FILL_RED 0x2
#define FILL_MASK 0xE
#define BORDER 0x100
#define BORDER_BLUE 0x800
#define BORDER_GREEN 0x400
#define BORDER_RED 0x200
#define BORDER_MASK 0xE00
#define B_SOLID 0
#define B_DOTTED 0x1000
#define B_DASHED 0x2000
#define STYLE_MASK 0x3000

const char * colors[8] = { "black", "red", "green", "yellow", "blue", "magenta",
"cyan", "white" };

struct box_props {
    bool opaque               : 1;
    unsigned int fill_color   : 3;
    unsigned int              : 4;
    bool show_border          : 1;
    unsigned int border_color : 3;
    unsigned int border_style : 2;
    unsigned int              : 2;
};

union Views /* 把数据看作结构或 unsigned short 类型的变量 */
{
    struct box_props st_view;
    unsigned short us_view;
};

void show_settings(const struct box_props * pb);
void show_settings1(unsigned short);
char * itobs(int n, char * ps);

int main(void)
{
    /* 创建 Views 联合,并初始化initialize struct box view */
    union Views box = { { true, YELLOW, true, GREEN, DASHED } };
    char bin_str[8 * sizeof(unsigned int) + 1];
    
    printf("Original box settings:\n");
    show_settings(&box.st_view);
    printf("\nBox settings using unsigned int view:\n");
    show_settings1(box.us_view);
    printf("bits are %s\n", itobs(box.us_view, bin_str));
    box.us_view &= ~FILL_MASK; /* 把表示填充色的位清0 */
    box.us_view |= (FILL_BLUE | FILL_GREEN); /* 重置填充色 */
    box.us_view ^= OPAQUE; /* 切换是否透明的位 */
    box.us_view |= BORDER_RED; /* 错误的方法 */
    box.us_view &= ~STYLE_MASK;/* 把样式的位清0 */
    box.us_view |= B_DOTTED; /* 把样式设置为点 */ 
    printf("\nModified box settings:\n");
    show_settings(&box.st_view);
    printf("\nBox settings using unsigned int view:\n");
    show_settings1(box.us_view);
    printf("bits are %s\n", itobs(box.us_view, bin_str));
    
    return 0;
}

void show_settings(const struct box_props * pb)
{
    printf("Box is %s.\n", pb->opaque == true ? "opaque" : "transparent");
    printf("The fill color is %s.\n", colors[pb->fill_color]);
    printf("Border %s.\n", pb->show_border == true ? "shown" : " not shown");
    printf("The border color is %s.\n", colors[pb->border_color]);
    printf("The border style is ");
    switch (pb->border_style)
    {
        case SOLID : printf("solid.\n"); break;
        case DOTTED: printf("dotted.\n"); break;
        case DASHED: printf("dashed.\n"); break;
        default    : printf("unknown type.\n");
    }
}

void show_settings1(unsigned short us)
{
    printf("box is %s.\n", (us & OPAQUE) == OPAQUE ? "opaque" : "transparent");
    printf("The fill color is %s.\n", colors[(us >> 1) & 07]);
    printf("Border %s.\n", (us & BORDER) == BORDER ? "shown" : "not shown");
    printf("The border style is ");
    switch (us & STYLE_MASK)
    {
        case B_SOLID  : printf("solid.\n"); break;
        case B_DOTTED : printf("dotted.\n"); break;
        case B_DASHED : printf("dashed.\n"); break;
        default       : printf("unknow type.\n");
    }
    printf("The border color is %s.\n", colors[(us >> 9) & 07]);
}

char  * itobs(int n, char * ps)
{
    int i;
    static const int size = CHAR_BIT * sizeof(int);
    
    for (i = size - 1; i >= 0; i--, n >>=1) // 7 -> 0000 0111
        ps[i] = (01 & n) + '0'; // 0000 0001
    ps[size] = '\0';
    
    return ps;
}

输出结果:

  • 程序清单15.5,align.c:

/* align.c -- 使用 _Alignof 和 _Alignas (C!!) */
#include <stdio.h>

int main(void)
{
    double dx;
    char ca;
    char cx;
    double dz;
    char cb;
    char _Alignas(double) cz;
    
    printf("char alignment: %zd\n", _Alignof(char));
    printf("double alignment: %zd\n", _Alignof(double));
    printf("&dx: %p\n", &dx);
    printf("&ca: %p\n", &ca);
    printf("&cx: %p\n", &cx);
    printf("&dz: %p\n", &dz);
    printf("&cb: %p\n", &cb);
    printf("&cz: %p\n", &cz);
    
    return 0;
} 

输出结果:

  • 编程练习:

题目1

方法一:使用位操作。代码示例15_1_1.c:

#include <stdio.h>
#include <ctype.h>  // 提供 isspace() 函数 
#include <string.h> // 提供 strchr() 函数 
#define SIZE 50

int get_bstr(char * st, int n);
char * del_space(char * st);
int btoi(char * st);

int main(void)
{
    char binstr[SIZE];
    int number;
    
    printf("Please input a binary string, [Enter] to quit: ");
    while(get_bstr(binstr, SIZE))
    {
        number = btoi(del_space(binstr));
        printf("Binary string %s is %d in decimal.\n", binstr, number);
        printf("Please input another binary string, [Enter] to quit: ");
    }
    
    return 0;
}

int get_bstr(char * st, int n) //通过指针获取字符串并返回字符串的长度 
{
    char ch;
    int i;
    
    //获取仅含 0或1 的字符串 ,注意通过 getchar() 获取的是字符而不是数字,加单引号 
    for (i = 0; i < n - 1 && (ch = getchar()) != '\n' && (ch == '1' || ch == '0'
        || isspace(ch)); i++)
        st[i] = ch;
    st[i] = '\0'; //最后一个字符设为空字符 
    //处理超出 n的大小的字符 
    if (ch != '\n')
        while (getchar() != '\n')
            continue;
            
    return i; 
}

char * del_space(char * st) // 删去字符中的空格(指针改变了字符串 st) 
{
    int i;
    char * find = NULL;
    
    while ((find = strchr(st, ' ')))
    {
        for (i = 0; find[i]; i++) // find[i] Equal to *(find + i) 
            find[i] = find[i + 1];
    }
    
    return st;
}

int btoi(char * st) // 通过按位或运算符生成一个目标数 
{
    int num = 0;
    int i;
    
    for (i = 0; st[i]; i++)
    {
        num <<= 1; // Equal to num = num << 1
        num |= (st[i] - '0'); // Equal to num = num | (st[i] - '0')
    }
    
    return num;
}

输出结果:

方法二:直接计算,两种方法。代码示例15_1_2.c:

#include <stdio.h>
#include <string.h> // 提供 strlen() 函数 
#define SIZE 50

int btoi(char * st);
int btoi1(char * st);

int main(void)
{
    char str[SIZE];
    
    printf("Please input a binary string: ");
    gets(str);
    printf("Binary string %s is %d in decimal.\n", str, btoi(str));
    printf("Binary string %s is %d in deciaml.\n", str, btoi1(str));
    
    return 0;
}

int btoi(char * st)
{
    int sum = 0;
    
    while (*st) // 读取字符时从左往右读取,每多读取一个数就增大两倍 
    {
        sum *= 2;
        sum += *st - '0';
        st++;
    }
    
    return sum;
}

int btoi1(char * st) // 从左往右理解二进制字符串,直观理解 
{
    int sum = 0;
    int len = strlen(st);
    int i, exp;
    
    for (i = len - 1, exp = 1; i >= 0; i--, exp *= 2)
        sum += exp * (st[i] - '0');
    
    return sum;
}

输出结果:

题目2

方法一:先转换为数字,运算完成后再转换为字符,递归实现。代码示例15_2_1.c:

#include <stdio.h>
#include <ctype.h>  // 提供 isspace() 函数 
#include <string.h> // 提供 strchr() 函数 
#include <stdlib.h> // 提供 EXIT_FAILURE 
#define SIZE 50

int btoi(char * st);
void print_bstr(unsigned int n);

int main(int argc, char * argv[])
{
    int num1, num2;
    
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s, binary_str1, binary_str2\n", *argv);
        exit(EXIT_FAILURE);
    }
    num1 = btoi(argv[1]);
    num2 = btoi(argv[2]);
    printf("num1 = %d\n", num1);
    printf("~num1 = %d\n", ~num1);
    
    printf("~%s is ", argv[1]);
    print_bstr(~num1);
    putchar('\n');
    printf("~%s is ", argv[2]);
    print_bstr(~num2);
    putchar('\n');
    
    printf("%s & %s is ", argv[1], argv[2]);
    print_bstr(num1 & num2);
    putchar('\n');
    
    printf("%s | %s is ", argv[1], argv[2]);
    print_bstr(num1 | num2);
    putchar('\n');
    
    printf("%s ^ %s is ", argv[1], argv[2]);
    print_bstr(num1 ^ num2);
    putchar('\n');
    
    return 0;
}

int btoi(char * st) // 通过按位或运算符生成一个目标数 
{
    int num = 0;
    int i;
    
    for (i = 0; st[i]; i++)
    {
        num <<= 1; // Equal to num = num << 1
        num |= (st[i] - '0'); // Equal to num = num | (st[i] - '0')
    }
    
    return num;
}

void print_bstr(unsigned int n) // 以二进制字符格式输出一个数的二进制格式 
{
    static long loop = 0; // 函数执行期间该值不变 
    
    if (!loop && !n)
    {
        putchar('0');
        return;
    }
    if (n)
    {
        loop++;
        print_bstr(n / 2);
    }
    else
        return;
    putchar('0' + (n % 2));
    if ((--loop % 4) == 0)
        putchar(' ');
}

输出结果:

方法二:先转换为数字,运算完成后再转换为字符,位操作实现。代码示例15_2_1.c:

#include <stdio.h>
#include <stdlib.h> // 提供 EXIT_FAILURE 

int bstr_to_dec(const char * str); // 2 进制字符串转换为 10 进制 
char *itobs(int n, char *str); // 将一个数转换为 2 进制字符串 

int main(int argc, char *argv[])
{
    char bstr[8 * sizeof(int) + 1];
    
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s binarynum1 binarynum2\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    int v1 = bstr_to_dec(argv[1]);
    int v2 = bstr_to_dec(argv[2]);
    printf("~%s = %s\n", argv[1], itobs(~v1, bstr));
    printf("~%s = %s\n", argv[2], itobs(~v2, bstr));
    printf("%s & %s = %s\n", argv[1], argv[2], itobs(v1 & v2, bstr));
    printf("%s | %s = %s\n", argv[1], argv[2], itobs(v1 | v2, bstr));
    printf("%s ^ %s = %s\n", argv[1], argv[2], itobs(v1 ^ v2, bstr));
    
    return 0;
}

int bstr_to_dec(const char * str)
{
    int val = 0;
    
    while (*str)
        val = val * 2 + ((*str++) - '0');
     
    return val;
}

char *itobs(int n, char *str)
{
    int sz = 8 * sizeof(int);
    
    for (int i = sz - 1; i >= 0; --i, n >>= 1)
        str[i] = (n & 1) + '0';
    str[sz] = '\0';
    
    return str;
}

输出结果:

方法三:按位直接计算,但该方法不适用于计算取反~。示例代码15_2_3.c:

#include <stdio.h>
#include <stdlib.h> //提供 EXIT_FAILURE 

void funca(char *a, char *b); // &运算 
void funcb(char *a, char *b); // ^运算 
void funcc(char *a, char *b); // |运算 
 
int main(int argc, char **argv)
{
    char ch;
    
    if(argc != 4)
    {
        fprintf(stderr, "Usage:%s [string] [string] [char]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    ch = argv[3][0];
    switch(ch)
    {
        case '1'://不能用位运算符作为识别符号,不符合命令行格式
            funca(argv[1], argv[2]);
            break;
        case '2':
            funcb(argv[1], argv[2]);
            break;
        case '3':
            funcc(argv[1], argv[2]);
            break;
        default: fprintf(stderr, "Wrong!\n");
            break;
    }
    
    return 0;
}

void funca(char *a, char *b)
{
    while(*a && *b)
    {
        int x = ((*a) - '0') & ((*b) - '0');
        putchar(x + '0');
        a++;
        b++;
    }
    putchar('\n');
}
 
void funcb(char *a, char *b)
{
    while(*a && *b)
    {
        int x = ((*a) - '0') ^ ((*b) - '0');
        putchar(x + '0');
        a++;
        b++;
    }
    putchar('\n');
}
 
void funcc(char *a, char *b)
{
    while(*a && *b)
    {
        int x = ((*a) - '0') | ((*b) - '0');
        putchar(x + '0');
        a++;
        b++;
    }
    putchar('\n');
}

输出结果:

题目3

方法一:直接按位&运算。示例代码15_3_1.c:

#include <stdio.h>

int count_openbit(unsigned int n);

int main(void)
{
    int num;
    
    printf("Please input an integer(q to quit): ");
    while (scanf("%d", &num))
    {
        while (getchar() != '\n')
            continue;
        printf("Here are %d bits opend in %d.\n", count_openbit(num), num);
        printf("Please input an integer(q to quit): ");
    }
    
    return 0;
}

int count_openbit(unsigned int n)
{
    int count = 0;
    
    while (n)
    {
        count += (n & 1);
        n >>= 1;
    }
    
    return count;
}

输出结果:

方法二:显示详细信息。示例代码15_3_2.c:

#include <stdio.h>
#define TEST_NUM 9

char * itobs(int n, char *str);
int onbits(int x);

int main(void)
{
    int x = TEST_NUM;
    char bstr[8 * sizeof(int) + 1];
    
    printf("%d(%s) has %d bit on.\n", x, itobs(x, bstr), onbits(x));
    
    return 0;
}

char *itobs(int n, char *str)
{
    int sz = 8 * sizeof(int);
    
    for (int i = sz - 1; i >= 0; --i, n >>= 1)
    {
        str[i] = (n & 1) + '0';
    }
    str[sz] = '\0';
    
    return str;
}

int onbits(int x)
{
    int sum = 0;
    
    for (int i = 8 * sizeof(int) - 1; i >= 0; --i)
    {
        sum += (x >> i) & 1;
    }
    
    return sum;
}

输出结果:

题目4

方法:移动数的位进行按位与运算,两个函数实现相同的功能。示例代码15_4.c:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TEST_VALUE 9 // 1001

bool isbit_open(int num, int pos);
bool isbit_open1(int num, int pos);

int main(void)
{
    int size = 8 * sizeof(int);
    int i;
    
    for (i = 0; i < size; i++)
        printf("The %dth of %d is %s.\n", i + 1, 
                TEST_VALUE, isbit_open(TEST_VALUE, i + 1) ? "opend" : "closed");
    
    return 0;
}

bool isbit_open(int num, int pos)
{
    if (pos <= 0)
    {
        fputs("The position can't be 0.", stderr);
        exit(1);
    }
    
    return (num & (1 << (pos - 1)));
}

bool isbit_open1(int num, int pos)
{
    if (pos <= 0)
    {
        fputs("The position can't be 0.", stderr);
        exit(1);
    }
    
    return (num >> (pos - 1)) & 1;
}

函数1或2输出结果:

题目5

方法:循环移动或者直接移动位,两种函数实现功能相同,示例代码15_5.c:

#include <stdio.h>
#include <limits.h> //Support for CHAR_BIT 
#define TEST_VALUE 9

char * itobs(int n, char *str);
unsigned int rotate_l(unsigned int num, int bits); // 将数的二进制位向左循环移动指定位 
unsigned int rotate_l_2(unsigned int num, int bits); 

int main(void)
{
    char bstr[CHAR_BIT * sizeof(unsigned int) + 1];
    
    printf("%d in binary is \n%s.\n", TEST_VALUE, itobs(TEST_VALUE, bstr));
    printf("After rotate to the left for 4 bits, the number in binary is \n%s.\n", 
            itobs(rotate_l(TEST_VALUE, 4), bstr));
    printf("After rotate to the left for 4 bits, the number in binary is \n%s.\n", 
            itobs(rotate_l_2(TEST_VALUE, 4), bstr));
            
    return 0;
    
}

char *itobs(int n, char *str)
{
    int sz = CHAR_BIT * sizeof(int);
    
    for (int i = sz - 1; i >= 0; --i, n >>= 1)
        str[i] = (n & 1) + '0';
    str[sz] = '\0';
    
    return str;
}

unsigned int rotate_l(unsigned int num, int bits)
{
    int i;
    
    for (i = 0; i < bits; i++) // 先保存最左侧的一位,再将数向右移动1位并或运算,如此循环 
        num = (num >> (CHAR_BIT * sizeof(unsigned int) - 1)) | (num << 1);
    
    return num;
}

unsigned int rotate_l_2(unsigned int num, int bits)
{
    static const int size = CHAR_BIT * sizeof(unsigned int);
    
    bits %= size;
    
    return (num << bits) | (num >> (size - bits));
}

输出结果:

题目6

方法:直接更改结构体中的内容即可。示例代码15_6.c:

#include <stdio.h>
#include <ctype.h> // 提供 isspace() 函数 
#include <string.h> // 提供 strchr() 函数 

typedef unsigned int uint;
typedef struct
{
    uint id : 8;
    uint sz : 7;
    uint at : 2;
    uint b  : 1;
    uint i  : 1;
    uint u  : 1;
} font;

static font ft = { 1, 12, 0, 0, 0, 0 };
const char * state[4] = { "off", "on" };
const char * alignment[7] = { "left", "center", "right" };

void eatline(void);
int get_first(void);
int get_choice(void);
void change_font(void);
void change_size(void);
void change_alignment(void);
void change_toggle(int ch);

int main(void)
{
    int ch;
    
    while ((ch = get_choice()) != 'q')
    {
        switch (ch)
        {
            case 'f':
                change_font();
                break;
            case 's':
                change_size();
                break;
            case 'a':
                change_alignment();
                break;
            case 'b':
            case 'i':
            case 'u':
                change_toggle(ch);
                break;
            default: fputs("Wrong!", stderr);
                break;
        }
        putchar('\n');
    }
    printf("Bye!\n");
    
    return 0;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

int get_first(void)
{
    int ch;

    do
    {
        ch = getchar();
    } while (isspace(ch));
    eatline();

    return ch;
}

int get_choice(void)
{
    int ch;

    printf("ID    SIZE    ALIGNMENT      B       I       U\n");
    printf("%-7u%-9u%-12s", ft.id, ft.sz, alignment[ft.at]);
    printf("%-8s%-8s%-8s\n", state[ft.b], state[ft.i], state[ft.u]);
    printf("f) change font        s) change size        a) change alignment\n");
    printf("b) toggle bold        i) toggle italic      u) toggle underline\n");
    printf("q) quit\n");

    while (ch = get_first(), NULL == strchr("fsabiuq", ch))
        printf("Please enter with f, s, a, b, i, u or q: ");
    
    return ch;
}

void change_font(void)
{
    int ch;
    uint id;
    
    printf("Enter font id (0-255): ");
    while (scanf("%u", &id) != 1)
    {
        while ((ch = getchar()) != '\n')
            putchar(ch);
        printf(" is not a id.\n");
        printf("Please enter a number such as 0, 5 or 255: ");
    }
    ft.id = id & 0XFF; // 确保不超过 255 
}

void change_size(void)
{
    int ch;
    uint sz;
    
    printf("Enter font sz (0-127): ");
    while (scanf("%u", &sz) != 1)
    {
        while ((ch = getchar()) != '\n')
            putchar(ch);
        printf(" is not a size.\n");
        printf("Please enter a number such as 0, 5 or 127: ");
    }
    ft.sz = sz & 0x7F;
}

void change_alignment(void)
{
    int ch;
    
    printf("Select alignment:\n");
    printf("l) left    c) center    r) right\n");
    while (ch = get_first(), NULL == strchr("lcr", ch))
        printf("Please enter with l, c or r: ");
    ft.at = (ch == 'l' ? 0 : ch == 'c' ? 1 : 2); // 理解一下 
}

void change_toggle(int ch)
{
    if (ch == 'b')
        ft.b ^= 1;
    else if (ch == 'i')
        ft.i ^= 1;
    else
        ft.u ^= 1;
}

输出结果(经测试暂时无误):

题目7

方法:用指定位代表相关状态,并操作相关位,一般是先清空相关位为零(&运算),然后放入目标位(|运算)。示例代码15_7.c:

#include <stdio.h>
#include <ctype.h> // 提供 isspace() 函数 
#include <string.h> // 提供 strchr() 函数 

typedef unsigned long ulong;
static ulong ft = 0x00001180; //题目初始; 0000 0000 0000 |0000 0001 |0001 100| 00| 0 | 0 | 0
//从右往左数, 第1位表示U, 第2位表示I, 第3位表示B, 第4至5位表示ALIGNMENT, 第6至第12位表示SIZE, 第13至20位表示ID
const char * state[4] = {"off", "on"};
const char * alignment[7] = {"left", "center", "right"};

void eatline(void);
int get_first(void);
int get_choice(void);
void change_font(void);
void change_size(void);
void change_alignment(void);
void change_toggle(int ch);

int main(void)
{
    int ch;
    
    while ((ch = get_choice()) != 'q')
    {
        switch (ch)
        {
            case 'f':
                change_font();
                break;
            case 's':
                change_size();
                break;
            case 'a':
                change_alignment();
                break;
            case 'b':
            case 'i':
            case 'u':
                change_toggle(ch);
                break;
            default: fputs("Error!", stderr); 
        }
        putchar('\n');
    }
    printf("Bye!\n");
    
    return 0;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

int get_first(void)
{
    int ch;

    do
    {
        ch = getchar();
    } while (isspace(ch));
    eatline();

    return ch;
}

int get_choice(void)
{
    int ch;

    printf("ID    SIZE    ALIGNMENT      B       I       U\n");
    printf("%-7lu%-9lu%-12s", (ft >> 12) & 0XFF, (ft >> 5) & 0x7F, alignment[(ft >> 3) & 0x03]);
    printf("%-8s%-8s%-8s\n", state[(ft >> 2) & 1], state[(ft >> 1) & 1], state[ft & 1]);
    printf("f) change font        s) change size        a) change alignment\n");
    printf("b) toggle bold        i) toggle italic      u) toggle underline\n");
    printf("q) quit\n");

    while (ch = get_first(), NULL == strchr("fsabiuq", ch))
        printf("Please enter with f, s, a, b, i, u or q: ");
        
    return ch;
}

void change_font(void)
{
    int ch;
    ulong id;
    
    printf("Enter font id (0-255): ");
    while (scanf("%lu", &id) != 1)
    {
        while ((ch = getchar()) != '\n')
            putchar(ch);
        printf(" is not a id.\n");
        printf("Please enter a number such as 0, 5 or 255: ");
    }
    id &= 0XFF, id <<= 12;
    for (int i = 12; i < 20; ++i)
        ft &= ~(ulong)(1 << i); //将指定位 置为零 
    ft |= id; //填入目标位
}

void change_size(void)
{
    int ch;
    ulong sz;
    
    printf("Enter font sz (0-127): ");
    while (scanf("%lu", &sz) != 1)
    {
        while ((ch = getchar()) != '\n')
            putchar(ch);
        printf(" is not a size.\n");
        printf("Please enter a number such as 0, 5 or 127: ");
    }
    sz &= 0X7F, sz <<= 5;
    for (int i = 5; i < 12; ++i)
        ft &= ~(ulong)(1 << i);
    ft |= sz;
}

void change_alignment(void)
{
    int ch;
    
    printf("Select alignment:\n");
    printf("l) left    c) center    r) right\n");
    while (ch = get_first(), NULL == strchr("lcr", ch))
        printf("Please enter with l, c or r: ");
    ft &= ~(ulong)(1 << 3), ft &= ~(ulong)(1 << 4);
    ft = ft | (ch == 'c' ? (ulong)(1 << 3) : ch == 'r' ? (ulong)(1 << 4) : 0);
}

void change_toggle(int ch)
{
    if (ch == 'b')
    {
        if (ft & 0x04)
            ft &= ~(ulong)(0x04);
        else
            ft |= (ulong)(0x04);
    }
    else if (ch == 'i')
    {
        if (ft & 0x02)
            ft &= ~(ulong)(0x02);
        else
            ft |= (ulong)(0x02);
    }
    else
    {
        if (ft & 0x01)
            ft &= ~(ulong)(0x01);
        else
            ft |= (ulong)(0x01);
    }
}

输出结果:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值