C学习笔记 位操作 20210330

用法: 关闭位(清空位)

假设mask只有1号位为1

flags = flags & ~mask;

mask中为1的位都被设置清空
简化形式:

flags &= ~mask;

用法: 切换位

使用按位异或运算符。如果mask 为1, 1^ mask 为0, 0^mask为1.

(00001111) ^ (10110110)
// 结果为
(10111001)

用法: 检查位的值

if ((flags & mask) == mask)
	puts("Wow");

如果mask对应的位上为1, 则打印wow。

移位运算符

  1. 左移 :<<
  2. 右移: >>
  /* 位操作显示二进制*/
#include "ctest.h"
#include <stdio.h>
#include <limits.h>    //提供CAHR_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-numric 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;
	const static int size = CHAR_BIT * sizeof(int);

	for (i = size - 1; i >= 0; i--, n >>= 1)
		ps[i] = (01 & n) + '0';
	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(' ');
	}
}

limits.h 中CAHR_BIT 宏表示char中的位数
CHAR_BIT * sizeof(int) 表示int类型的位数

切换一个值中的后n位

使用^组合掩码和待切换的值, 即可切换该值的最后n位, 其他位不变。

int invert_end (int num, int bits)
{
	int mask = 0;
	int bitval = 1;

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

mask的后n位在循环中被设置为1, 最后num ^ mask运算即的所需结果。

#include <stdio.h>
#include <limits.h>
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-numric 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;
	const static int size = CHAR_BIT * sizeof(int);

	for (i = size - 1; i >= 0; i--, n >>= 1)
		ps[i] = (01 & n) + '0';
	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;
}

位字段(bit field)

位字段是一个unsigned int 或signed int 类型变量中一组相邻的位。
位字段通过一个结构声明来建立:

struct{
	unsigned int autfd: 1;
	unsigned int bldfc: 1;
	unsigned int undln: 1;
	unsigned int itals: 1;
}prnt;

prnt中包含4个1位的字段, 变量prnt被储存在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; 
};

c以unsigned int作为位字段结构的基本布局单元.

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

/*线的样式*/
#define SOLTD 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 WHITH (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)
{
	struct box_props box = { true, YELLOW, true, GREEN, DASHED };
	printf("Original box settings:\n");
	show_settings(&box);
	box.opaque = false;
	box.border_color = MAGENTA;
	box.border_style = SOLTD;
	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 SOLTD:  printf("solid.\n"); break;
	case DOTTED: printf("dotted\n"); break;
	case DASHED: printf("dashed\n"); break;
	default:     printf("unknown type.\n"); break;
	}
}

位字段和按位运算符

通过一个联合把结构方法和位方法放在一起

union Views
{
	struct box_props st_view;
	unsigned short us_view;
};
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#include <stdbool.h>

/*线的样式*/
#define SOLTD 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 WHITH (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
{
	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)
{
	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;
	box.us_view |= (FILL_BLUE | FILL_GREEN);
	box.us_view ^= OPAQUE;
	box.us_view |= BORDER_RED;
	box.us_view &= ~STYLE_MASK;
	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 SOLTD:  printf("solid.\n"); break;
	case DOTTED: printf("dotted\n"); break;
	case DASHED: printf("dashed\n"); break;
	default:     printf("unknown type.\n"); break;
	}
}

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)
		ps[i] = (01 & n) + '0';
	ps[size] = '\0';
	return ps;
}

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("unknown type.\n"); break;
	}
	printf("The border color is %s.\n", colors[(us >> 9) & 07]);
}

warning:vs上操作失败, 不推荐对字段进行位操作运算

对齐特性(c11)

_Alignof运算符给出一个类型的对齐要求,

size_t d_align = _Alignof(float);

若d_align 值为4, 即要求float类型的对齐要求是4, 一般对齐值都应该是2的非负整数次幂, 较大的对齐值称为stricter或stronger, 较小的对齐值称为waker。
可以使用_Alignas指定一个变量或类型的对齐值

_Alignas(double) char c1;
_Alignas(8) char c2;
unsigned char _Alignas(long double) c_arr[sizeof(long double)];
#include <stdio.h>
#include <stdlib.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 aligment:	%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);
}

double对齐值为8, 其地址的类型对齐可以被8整除。
由于windows堆的特性, Windows不支持c11在stdlib.h中添加的对于动态对齐的内存的内存分配函数

void *aligned_alloc(size_t aligment, size_t size);

建议使用

void * _aligned_malloc(
    size_t size,
    size_t alignment
);

参数size为所需的字节数, 其值应该是aligment的整数倍, aligment代表指定的对齐, 同样, 要使用free()来释放内存。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值