第15章 位操作

位操作的方式有两种: 一种是位运算符。一种是位字段

位运算符

  1. 二进制反码或按位取反: ~
    运算符将1变为0,0 变为1
    ~(10011010) //表达式
    (01100101) //结果值
#include <stdio.h>

int main(void)
{
  unsigned char val = 2;
  unsigned  char newval;
  newval = ~val;
  printf(" %d \n", val);    //注意该操作并不会改变原val的值
  printf(" %d \n", newval);

  return 0;
}

  1. 按位与: &
    逐位对比两个运算对象,生成一个新值。对于每个位,只有都为1时结果才为1
    (10010011) & (00111101)
    (00010001) //结果
    C提供运算符: &=
    val &= 0377;
    val = val & 0377;
    这两个相等

  2. 按位或: |
    逐位对比两个运算对象,生成一个新值。对于每个位,只要有一位是一就都是一
    (10010011) | (00111101)
    (10111111) //结果
    C提供运算符: |=
    val |= 0377;
    val = val | 0377;
    这两个相等

  3. 按位异或: ^
    逐位对比两个运算对象,对于每个位,如果两个运算对象中相应的位一个为1(但不是两个位1),结果为1(简单来说就是,这两个位必须不相同)
    (10010011) ^ (00111101)
    (10101110) //结果
    C提供运算符: ^=
    val ^= 0377;
    val = val ^ 0377;

移位运算符

  1. 左移: <<
    将其左侧运算对象每一位的值向左移动其右侧运算符对象指定的位数,左侧运算对象移出左末端位的值丢失,用0填充空出的位置
    (10001010) << 2
    (00101000) //结果值
  2. 右移: >>
    对于无符号类型与左移一样,对于有符号类型,其结果取决于机器。空出的位置可用0填充,或用符号位(即,最左端的位)的副本填充:

位字段

操作位的第二种方法是位字段。位字段是一个signed int 或unsigned int变量中的一组相邻的位

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

1

/**
 * 编写一个函数,把二进制字符串转换为一个数值。例如,有下面语句:
 * char * pbin = "01001001"
 * 那么把pbin作为参数传递给该函数后,他应该返回一个int类型的值25
*/

#include <stdio.h>
#include <math.h>
#include <string.h>

int twototen(const char * ps);

int main(void)
{
    int num;
    char * pbin = "01001001";
    num = twototen(pbin);
    printf("%d", num);
    return 0;
}

int twototen(const char * ps)
{
    int val = 0;
    while (*ps != '\0')
    {
        val = 2 * val + (*ps++ - '0');
    }
    return val;
}

2

/**
 * 编写一个程序, 通过命令行参数读取两个二进制字符串,对这两个二进制数使用~运算符、&
 * 运算符、|运算符和^运算符,并以二进制字符串形式打印结果
*/

#include <stdio.h>
#include <limits.h>

int twototen(const char *);
char * itobs(int , char *);

int main(int argc, char const *argv[])
{
    int n1, n2;
    char bran[CHAR_BIT * sizeof(int) + 1];

    n1 = twototen(argv[1]);
    n2 = twototen(argv[2]);

    printf("~%s : %s\n", argv[1], itobs(~n1, bran));
    printf("~%s : %s\n", argv[2], itobs(~n2, bran));
    printf("&运算: %s\n", itobs((n1&n2), bran));
    printf("|运算: %s\n", itobs((n1|n2), bran));
    printf("^运算: %s\n", itobs((n1^n2), bran));
    return 0;
}

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

char * itobs(int n, char *str)
{
    int i;
    const static int size = CHAR_BIT * sizeof(int);

    for ( i = size - 1; i >= 0; i--, n >>= 1)
    {
        str[i] = (01 & n) + '0';
    }
    str[size] = '\0';
    return str;
}

3

/**
 * 编写一个函数,接受一个int类型的参数,并返回该参数中打开位的数量。在一个程序中测试该函数
*/

#include <stdio.h>
#include <limits.h>

int on_off(int n);

int main(void)
{
    int num;
    int i;

    puts("Please enter num");
    scanf("%d", &i);
    num = on_off(i);
    printf("%d", num);
    return 0;
}

int on_off(int n)
{
    int count = 0;
    int i;
    const static int size = CHAR_BIT * sizeof(i);
    
    for ( i = 0; i < size; i++, n >>= 1)
    {
        if (n & 01)
        {
            count++;
        }
    }
    return count;
}

4

/**
 * 编写一个程序,接受两个int类型的参数: 一个是值;一个是位的位置。如果指定
 * 的位置为1,该函数返回1;否则返回0.在一个程序中测试该函数
*/

#include <stdio.h>
#include <limits.h>

int localtion(int, int);

int main(void)
{
    int value, num;
    int result;
    puts("Please enter values");
    scanf("%d", &value);
    puts("Please enter numbers");
    scanf("%d", &num);
    result = localtion(value, num);
    printf("%d", result);

    return 0;
}

int localtion(int value, int num)
{
    value >>= (num-1);
    if (value & 1)
    {
        return 1;
  }
    return 0;    
}

5

/**
 * 编写一个函数,把一个unsigned int 类型值中的所有位向左旋转指定数量的位。例如
 * rotate_l(x, 4)把x中所有位同左移4个位置,而且从最左端移出的位会重写出现在右端
 * 也就是说,把高阶位移出的位放入低阶位。在一个程序中测试该函数
*/

#include <stdio.h>

void rotate_l(int x, int n);

int main(void)
{
    unsigned int num;
    unsigned int n;
    puts("Please enter num");       //要被移动的数字
    scanf("%u", &num);
    puts("Please enter nums");    //移动位数
    scanf("%u", &n);
    rotate_l(num, n);
    return 0;
}

void rotate_l(int x, int n)
{
    unsigned int val;
    val = x >> (32 - n);
    x <<= n;
    x |= val;
    printf("%u", x);
}

6

/**
 * 设计一个位字段结构以存储下面的信息.
*/
#include <stdio.h>
#include <stdbool.h>
struct set_word
{
    unsigned int typeface       : 8;
    unsigned int bigorsmall     : 7;
    unsigned int                : 1;    //作为间隙
    unsigned int aline          : 3;
    unsigned int                : 1;
    bool bold                   : 1;
    bool italic                 : 1;
    bool underline              : 1;
    unsigned int                : 1;
};

const char * italics[8] = {"left", "middle", "right"};  //等会打印用到
const char * on_off[3] = {"off", "on"};

void show_news(struct set_word * pst);      //展示字体信息
char menu(void);            //展示菜单选项
char get_ch(void);          //读取选项的函数
void chang_font(struct set_word * pst);     //改变字体
void chang_size(struct set_word * pst);     //改变大小
void chang_alignment(struct set_word * pst);    //对齐方式
void change_italic(struct set_word * pst);      //是否斜体
void change_bold(struct set_word * pst);        //是否实线
void change_under(struct set_word * pst);       //有没有下划线

int main(void)
{
    char ch;
    struct set_word sets = {
        1, 12, 0, 0, 0, 0
    };
    show_news(&sets);
    while ((ch = menu()) != 'q')
    {
        switch (ch)
        {
        case 'f':
            chang_font(&sets);
            break;
        case 's':
            chang_size(&sets);
            break;
        case 'a':
            chang_alignment(&sets);
            break;
        case 'b':
            change_bold(&sets);
            break;
        case 'i':
            change_italic(&sets);
            break;
        case 'u':
            change_under(&sets);
            break;
        default:
            puts("Error!");
            break;
        }
        show_news(&sets);
    }
    
    show_news(&sets);
    return 0;
}

void show_news(struct set_word * pst)
{
    puts("ID    SIZE    ALIGNMENT    B       I       U");
    printf("%-8d%-8d%-8s  %-8s%-8s%-8s\n", pst->typeface,
    pst->bigorsmall, italics[pst->aline], on_off[pst->bold], on_off[pst->italic],
    on_off[pst->underline]);
}

char menu(void)
{   
    char ch;-
    puts("f)change font    s)change size    a)change alignment");
    puts("b)toggle bold    i)toggle italic  u)toggle underline");
    puts("q)quit");
    ch = get_ch();
    return ch;
}

char get_ch(void)
{
    char ch;
    scanf("%c", &ch);
    while (getchar() != '\n')
        continue;
    return ch;
}

void chang_size(struct set_word * pst)
{
    unsigned int n;
    scanf("%u", &n);
    while (getchar() != '\n')
        continue;
    if (n > 127)
    {
        n &= 127;    //二进制是1111111
    }
    
    pst->bigorsmall = n;

}

void chang_alignment(struct set_word * pst)
{
    char ch;
    puts("Select alignment:");
    puts("1)left   c)center    r)right");
    scanf("%c", &ch);
    while (getchar() != '\n')
        continue;
    switch (ch)
    {
    case 'l':
        pst->aline = 0;
        break;
    case 'c':
        pst->aline = 1;
        break;
    case 'r':
        pst->aline = 2;
        break;
    
    default:
        puts("Errorrrr!");
        break;
    }
}

void change_italic(struct set_word * pst)
{
    if (pst->italic == 0)
    {
        pst->italic = 1;
    }
    else
    {
        pst->italic = 0;
    }   
}

void change_bold(struct set_word * pst)
{
    if (pst->bold == 0)
    {
        pst->bold = 1;
    }
    else
    {
        pst->bold = 0;
    }   
}
void change_under(struct set_word * pst)
{
    if (pst->underline == 0)
    {
        pst->underline = 1;
    }
    else
    {
        pst->underline = 0;
    }   
}

void chang_font(struct set_word * pst)
{
    unsigned int n;
    scanf("%u", &n);
    while (getchar() != '\n')
        continue;
    if (n > 255)
    {
        n &= 255;    //二进制是1111111
    }
    
    pst->typeface = n;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容