当前位置:   article > 正文

C-study(十五)

C-study(十五)

二进制、位、字节

位操作

单独操作变量中的位
发送字节控制硬件设备
与文件相关的操作系统信息、通过特定位表明特定项
压缩和加密操作直接处理位

二进制0、1:表示内存和寄存器中位的开闭状态

二进制数

十进制:基于10的幂、2157:2* 103+1* 102+5* 101+7* 100
二进制:基于2的幂、1101:1* 23+1* 22 +0* 21+1* 20 =13(十进制)

字节:储存系统字符集所需大小、通常8位、可以是9位、16位或其他值

8位字节:描述存储器芯片和数据传输率

从左往右:高阶位->低阶位

8位字节最大值:11111111
128+64+32+16+8+4+2+1=255
最小值:00000000

1字节存储范围 0~255(unsigned char)或-128~+127(signed char) 共256个值
在这里插入图片描述

有符号数

符号量表示:
最高阶位存储符号0正\1负,右7位表示数字
10000001表示-1
00000001表示1
表示范围 -127~+127
有+0和-0

二进制补码
最高位为0、右7位表示数字、0~+127
最高位为1、右7位按位取反+1、-128~-1
11111111表示-1
1000000表示-128

二进制反码
最高位为0、右7位表示数字、0~+127
最高位为1、右7位按位取反、-127~-0
11111110表示-1
11111111表示-0

浮点数

十进制小数、0.527:5/10+2/100+7/1000
二进制小数、.101:1/2+0/4+1/8 =0.625(十进制)
二进制小数+二进制指数

其他进制数

八进制

0-7表示数字、基于8的幂:451->4 * 82+5 * 81+1 * 80=297(十进制)

每个8进制位对应3个2进制位:0377->011111111
转换时可以去掉最高位的0、不可以去掉中间和低位0

缺点:用3倍的二进制数表示

在C语言中八进制前面加0:0451
在这里插入图片描述

十六进制

0-9、A-F表示0-15、基于16的幂:A3F->10* 162+3* 161+15*160=2623(十进制)

每个16进制对应4个2进制数
1字节对应2个16进制、前4位和后4位

在C语言中十六进制前面加0x、字母大小写不分:0xa3f、0xA3F
在这里插入图片描述

按位运算符

用于整型数据、针对每一个位进行
常规逻辑运算符(&&、|| 和! )操作的是整个值

按位取反

一元运算符~:1->0、0->1

unsigned char val = 2; // 二进制 0000 0010
unsigned char newval = ~val; // 不会改变val的值val:2、返回新值、newval:253(1111 1101)
val = ~val;            // 改变val的值
  • 1
  • 2
  • 3

按位与

&:逐位比较2个运算对象、生成一个新值
对应位都为1时、结果为1、其他情况结果为0
1 0 0 1 0 0 1 1 &
0 0 1 1 1 1 0 1 =
0 0 0 1 0 0 0 1

掩码

掩码:设置为开1、关0的位组合、需要隐藏的位设置为0

#define MASK 00000010
unsigned char flag;
	// 掩码
    flag &= MASK;
    /* &=运算符、相当于flag = flag & MASK;
    &0=0 &1=保持不变、flag第二位保持不变、其他置0
    用掩码中的0隐藏flag中的位、只有为1的位可见:用掩码覆盖在flags上 */

    // ch &= 0xff; // 保持最后8位不变、其他位都设置为0、无论原值有多少位、结果设置为1个8位字节
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

关闭位

关闭指定位

// 关闭位
flag &= ~MASK;
/* &=运算符、相当于 flag = flag & ~MASK;
~MASK:第二位为0、其他为1、11111101
&0=0 &1=保持不变、flag第二位置0、其他不变*/
  • 1
  • 2
  • 3
  • 4
  • 5

检查位的值

检查某一位的值、不可以直接==(判断整体值)

// 检查位的值
if ((flag & MASK) == MASK)
/*00000010
&0=0 &1=保持不变、flag第二位保持不变、其他置0
再比较、只比较第二位
&优先级低于==,加括号
要注意掩码宽度至少和覆盖的值宽度相等*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

按位或

|:逐位比较2个运算对象、生成一个新值
对应位都为0时、结果为0、其他情况结果为1
1 0 0 1 0 0 1 1 |
0 0 1 1 1 1 0 1 =
1 0 1 1 1 1 1 1

打开位

打开特定值、其他值不变

// 打开位
flag |= MASK;
/* |=运算符、相当于 flag = flag | MASK; 00000010
|0=保持不变 |1=1、flag第二位置1、其他不变 */
  • 1
  • 2
  • 3
  • 4

按位异或

^:逐位比较2个运算对象、生成一个新值
对应位不同时、结果为1、其他情况结果为0
1 0 0 1 0 0 1 1 ^
0 0 1 1 1 1 0 1 =
1 0 1 0 1 1 1 0

切换位

关闭已打开的位、打开已关闭的位

// 切换位
flag ^= MASK;
/* ^=运算符、相当于 flag = flag ^ MASK; 00000010
^0=保持不变 ^1=取相反、flag取第二位相反、其他不变*/
  • 1
  • 2
  • 3
  • 4

移位运算符

2进制的每一位同时移动

左移 <<

number << n、number 向左移动 n位、number*2n
左边溢出的值丢掉、右边空出的值填0
不改变运算对象
(1 0 0 0 1 0 1 0)<< 2
0 0 1 0 1 0 0 0

int stonk = 1;
int onkoo;
onkoo = stonk << 2; // 左移之后的值赋给新变量、原变量不变
stonk <<= 2; //  stonk = stonk << 2; 左移并赋值
  • 1
  • 2
  • 3
  • 4

右移 >>

number >> n、number 向右移动 n位、number/2n(number>=0)
右边溢出的值丢掉、左边空出的值填0(无符号类型)或符号位(有符号类型部分机器)
不改变运算对象

无符号类型
(1 0 0 0 1 0 1 0) >>2
0 0 1 0 0 0 1 0

有符号类型
(1 0 0 0 1 0 1 0) >>2
0 0 1 0 0 0 1 0 在某些系统中的结果
1 1 1 0 0 0 1 0 在另些系统中的结果

#include <limits.h> //提供 CHAR_BIT的定义
char *itobs(int, char *);
void show_bstr(const char *);
int invert_end(int num, int bits);
    int sweet = 1;
    int ooosw;
    ooosw = sweet << 2; // 右移之后的值赋给新变量、原变量不变
    sweet <<= 2;        // sweet = sweet << 2; 左移并赋值

    #define BYTE_MASK 0xff
    unsigned long color = 0x002a162f;
    unsigned char blue, green, red;
    red = color & BYTE_MASK;          // 只取低8位
    green = (color >> 8) & BYTE_MASK; // 取中间8位、将8位颜色移动至低字节、掩码把低字节赋给指定变量
    blue = (color >> 16) & BYTE_MASK; // 取高8位

    /* binbit.c --使用位操作显示二进制*/
    char bin_str[CHAR_BIT * sizeof(int) + 1];
    /* CHAR_BIT表示每字节的位数 sizeof(int)返回int类型占字节数
    CHAR_BIT * sizeof(int) 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);//取反后4位
        printf("Inverting the last 4 bits gives\n");
        show_bstr(itobs(number, bin_str));
        putchar('\n');
    }
    puts("Bye ! ");

char *itobs(int n, char *ps)
{
    int i;
    const static int size = CHAR_BIT * sizeof(int);
    for (i = size - 1; i >= 0; i--, n >>= 1)
        // i-- 数组下标 n>>=1 右移一位、循环处理n中新的最右端的值
        ps[i] = (01 & n) + '0';
    /* 01:八进制掩码  1&n 0x1&n
    即001(二进制)&n、只保留n最后一位的值、0、1
    +'0' 转换为字符'0'、'1'
    结果放在数组倒数第二个元素开始*/
    ps[size] = '\0'; // 最后一个元素用来放空字符
    return ps;
    // 修改ps之后返回ps、字符串首地址可作为printf参数
}
void show_bstr(const char *str)
{ /*4位一组显示二进制字符串*/
    int i = 0;
    while (str[i]) /*不是一个空字符*/
    {
        putchar(str[i]);
        if (++i % 4 == 0 && str[i])
            putchar(' ');
    }
}
int invert_end(int num, int bits)
{// 取反num的后bit位  ~num 取反num里的所有位
    int mask = 0; // 所有位都为0
    int bitval = 1;
    while (bits-- > 0) // 循环bits次,每次操作一位
    {
        mask |= bitval; // bitval 1对应的位置设置为1
        bitval <<= 1;
    }
    return num ^ mask; // 取反num的右bit位
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

位字段

signed int 或 unsigned int 类型变量中相邻的位
C99和C11新增_Bool类型的位字段

结构声明建立字段,给字段提供标签和宽度
内含字段的结构允许在一个存储单元存多个字段

unsigned int 位字段结构的基本布局单元、即使结构中只有一个1位字段的成员、结构大小=sizeof(unsigned int)

struct
{// 通过结构声明建立、为每个字段提供标签和宽度
unsigned int autfd : 1; // 标签+宽度、只有一位、只能赋值为0、1
    unsigned int bldfc : 1;
    unsigned int undln : 1;
    unsigned int itals : 1;
} prnt; // prnt包含4个1位的字段、存储在1个int大小的内存单元、只使用了其中4位
prnt.itals = 0; // 结构成员运算符.单独给字段赋值
prnt.undln = 1;

struct
{
    unsigned int code1 : 2;
    unsigned int code2 : 2;
    unsigned int code3 : 8;
    /*总位数超过1个unsigned int大小时、用下一个unsigned int的存储位置
    1个字段不会跨越2个unsigned int之间的边界、会自动移动跨界字段、保持边界对齐、前一个unsigned int会留下洞*/
} prcode; // 两个2位的字段和一个8位的
prcode.code1 = 0;
prcode.code2 = 3;
prcode.code3 = 102; // 字段赋值不可超过字段范围

struct
{
    unsigned int fieldl : 1;
    unsigned int : 2; // 未命名字段宽度填充未命名的洞
    unsigned int field2 : 1;
    unsigned int : 0; // 宽度为0的未命名字段使下一字段与下一个整数对齐
    unsigned int field3 : 1;
    /*在stuff.field1和stuff.field2之间,有一个2位的空隙、
    stuff.field3将储存在下一个unsigned int 中*/
} stuff;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

方框属性程序示例

位字段方式

/*fields.c-- 定义并使用字段 */
#include <stdbool.h> // c99定义了bool(_Bool别名)、true、false
// 位字段符号常量
/*线的样式 3种样式 2个单位(共4种组合)表示*/
#define SOLID 0
#define DOTTED 1
#define DASHED 2
/*三原色*/
#define BLUE 4
#define GREEN 2
#define RED 1
/*混合色 共8种颜色 3个单位8种组合表示*/
#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
{
    unsigned int opaque : 1;     // 或者bool(c99 以后、不兼容时bool占1字节、加字节对齐导致结构体从4字节变为8字节) 方框透明、不透明
    unsigned int fill_color : 3; // 方框填充颜色
    unsigned int : 4;
    unsigned int show_border : 1;  // 或者bool(c99 以后) 边框可见、隐藏
    unsigned int border_color : 3; // 边框颜色
    unsigned int border_style : 2; // 边框样式 0,1,2
    unsigned int : 2;
}; /* 前8位方框属性、后8位边框属性、空隙用未命名字段填充、
共占用16位,在系统中占sizeof(unsigned int)位、4位*/

void show_settings(const struct box_props *pb);

    struct box_props box = {true, YELLOW, true, GREEN, DASHED};
    /* 创建并初始化unsigned int大小的box_props结构
    初始化字段结构与普通结构语法相同
    */
    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);
    getchar();
    
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");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

在这里插入图片描述

按位运算符方式

联合中结构和变量:涉及到结构载入顺序、第1字段载入最高阶位还是最低阶位

/*按位方法中用到的符号常量*/
#define OPAQUE 0x1    // 0号位
#define FILL_BLUE 0x8 // 方框颜色的位置信息、3号位为1、#define FILL_BLUE 1<<3 编译时求值
#define FILL_GREEN 0x4
#define FILL_RED 0x2
#define FILL_MASK 0xE // 方框颜色掩码
#define BORDER 0x100
#define BORDER_BLUE 0x800 // 边框颜色的位置信息、11号位为1、位置不同不可以和方框颜色一起显示
#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 // 边框样式掩码
/*枚举替代#define、可以不声明标记
enum
{
    OPAQUE = 0x1,
    FILL_BLUE = 0x8,
    FILL_GREEN = 0x4,
    FILL_RED = 0x2,
    FILL_MASK = 0xE,
    BORDER = 0x100,
    BORDER_BLUE = 0x800,
    BORDER_GREEN = 0x400,
    BORDER_RED = 0x200,
    BORDER_MASK = 0xE00,
    B_DOTTED = 0x1000,
    B_DASHED = 0x2000,
    STYLE_MASK = 0x3000
};*/
union Views /*4字节的联合*/
{// 涉及到结构载入前16位和后16位的区别、unsigned short存在后16位
    struct box_props st_view; // 数据看作结构、4字节、只有2字节有数据
    unsigned short us_view;   // 数据看作unsigned short类型的变量、2字节
};
void show_settings1(unsigned short);

    printf("sizeof(unsigned int):%d\nsizeof(bool):%d\nsizeof(unsigned short):%d\nsizeof(struct box_props):%d\nsizeof(union Views):%d\n",
           sizeof(unsigned int), sizeof(bool), sizeof(unsigned short), sizeof(struct box_props), sizeof(union Views));
    
    /*创建views联合,并初始化initialize struct box view
    unsigned int变量存储*/
    union Views view = {{true, YELLOW, true, GREEN, DASHED}}; // 参考联合初始化
    char bin_str[CHAR_BIT * sizeof(unsigned int) + 1];
    printf("\noriginal view settings : \n");
    show_settings(&view.st_view); // 使用位字段box_props类型的结构
    printf("\nView settings using unsigned int view : \n");
    show_settings1(view.us_view); // 使用unsigned short类型的
    printf("bits are %s\n", itobs(view.us_view, bin_str));

    view.us_view &= ~FILL_MASK;               /*把之前表示填充色的位清0 位运算符访问*/
    view.us_view |= (FILL_BLUE | FILL_GREEN); /*重置填充色 */
    view.us_view ^= OPAQUE;                   /*切换是否透明的位*/
    view.us_view |= BORDER_RED;               /*错误的方法、不清0直接设置会被原来的位影响*/
    view.us_view &= ~STYLE_MASK;              /*把样式的位清0*/
    view.us_view |= B_DOTTED;                 /*把样式设置为点*/
    printf("\nModified view settings : \n");
    show_settings(&view.st_view);
    printf("\nView settings using unsigned int view : \n");
    show_settings1(view.us_view);
    printf("bits are %s\n", itobs(view.us_view, bin_str));
    getchar();
    
void show_settings1(unsigned short us)
{
    printf("us is %d.\n", 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("unknown type. \n");
    }
    printf("The border color is %s.\n", colors[(us >> 9) & 07]);
    // us >> 9把边框颜色右移至最右端(0-2号位)&111(2进制)、关闭其他位
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

在这里插入图片描述

对齐(C11)

对齐:安排对象在内存的位置
对齐值:2的非负整数次幂
_Alignas 指定变量对齐值,指定的对齐值不可以小于基本对齐值
_Alignof(类型); //获取对其要求

#include<stdalign.h>//alignas alignof 别名
#include <stdlib.h> //void *aligned_alloc(size_t alignment, size_t size);
// align.c-- 使用_Alignof和_Alignas(c11)
    double dx;//8,地址可以整除8
    char ca;//1
    char cx;
    double dz;
    char cb;
    char _Alignas(double) cz; // 8 或者_Alignas(double) char cz;
    // float _Alignas(char) fz; // error指定对齐值不可小于默认对齐值
    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);// 1
    printf("&cz : %p\n", &cz);// 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号