第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;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容