#if 0
@file: littleEndian.c
@desc: 位操作的实验代码
gcc -W -Wall -pedantic -std=c99 -m32 -o bits littleEndian.c
1.小端字节序
低地址存放数据的低字节,高地址存放的是字数据的高字节
例如 char sr[] = {0X12, 0X34, 0X56, 0X78};
强转为整数后变为 int num = 0X78563412;
The Intel x86 and AMD64 / x86-64 series of processors use the little-endian format.
x86、MOS Technology 6502、Z80、VAX、PDP-11等处理器为小端序;
Motorola 6800、Motorola 68000、PowerPC 970、System/370、SPARC(除V9外)等处理器为大端序;
ARM、PowerPC(除PowerPC 970外)、DEC Alpha、SPARC V9、MIPS、PA-RISC及IA64的字节序是可配置的。
网络传输一般采用大端序,也被称之为网络字节序,或网络序。
许多新的处理器是双端法,大小端可配置,实际情况是一旦选择了操作系统,那么字节序也固定了下来.
比如ARM可以按大端小端处理,但这些芯片上的操作系统 Android IOS Linux 却只能运行小端。
小端序(先传低位)的串行协议 RS-232、RS-422、RS-485、USB、以太网(虽然高字节先传,但每一字节内低位先传)
https://en.wikipedia.org/wiki/Endianness
2.位运算 & | ^ ~
表达式 ~0 将生成全1的掩码,不管机器的字节大小是多少.
当 x=0x87654321,
A. x的最低位有效,其余位置0.[0x00000012] x & 0XFF
B. 除了 x 的最低位,其余位都取补.[0x789ABC12] x ^ ~0XFF
C. 最低位设置成全 1 . x | 0XFF
强制类型转换的结果保持位不变,只改变了解释这些位的方式
当声明一个常量时,默认有符号,要创建一个无符号常量,必须加上后缀字符 U 或 u.
无符号和有符号比较时,会转换为无符号, -1 将转换成最大值,比如 -1 < 1U,-1的二进制全为1,比 1u 大.
对于任意整数值x,求负 -x == ~x+1.
建议:位运算时加上括号.
3. 二进制转换成整数
比如一个 4 位的类型(w=4),最高位为符号位,权重 -2^(w-1). w为二进制位数,这里的 ^ 表示 2 的 w-1 次方.
0001 = -0*2^3 + 0*2^2 + 0*2^1 + 1*2^0 = 1
0101 = -0*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 5
1011 = -1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = -5
1111 = -1*2^3 + 1*2^2 + 1*2^1 + 1*2^0 = -1
4. 反码和补码
有符号类型用最高位表示,正数最高位0;负数最高位1;
负数另一种解释:用正数的反码加 1 表示(即用正数的`补码`表示),
例如,我们通过如下变换得到-7:
+7[0111],反码 -- > [1000],反码加1 -- > -7[1001].
最终这个 -7[1001] 即 +7[0111] 的补码。
假如一个机器`4`位,则:
正数范围`[0001]`~`[0111]`,即`1`-`7`,`[2^3-1]`
负数范围`[1000]`~`[1111]`,即`-8`至`-1`
5. 乘以常数
乘以2的整数次幂n,参照十进制乘以10的整数次幂,后面补0即可,二进制的话即左移n次.
x*14 ==> 14 = 2^3 + 2^2 + 2^1 ==> (x << 3) + (x << 2) + (x << 1)
https://graphics.stanford.edu/~seander/bithacks.html
6. 利用位操作简化代码
/**** 求2的幂 ****/
1 << 2; 4, 即 2的2次方
1 << 10; 1024, 即 2的10次方
/**** 使用 ^ 切换变量 0 或 1 ****/
--- before ---
if (toggle) toggle = 0;
else toggle = 1;
或者 togle = toggle ? 0 : 1;
--- after ---
toggle ^= 1;
/**** 使用 !! 将数字转为布尔值 ****/
!!7; true
!!0; false
/**** 使用^判断符号是否相同 ****/
(a ^ b) >= 0; true 相同; false 不相同
/**** 使用^来检查数字是否不相等 ****/
--- before ---
if (a !== 1171) {...}
--- after ---
if (a ^ 1171) {...}
7. 宏
// https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit
/* a: target variable, b: bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1
#endif
#include <stdio.h>
/************ 大小端测试 *************/
static char isLittleEndian() {
char *str = "abcd";
/* a 会放在num的低位, num 表示dcba */
int *num = (int *)str;
return (*num & 0XFF) == str[0];
}
static char _isLittleEndian() {
int num = 1;
/* 1 会放在str的低地址str[0]中 */
char *str = (char *)#
return str[0];
}
static void test1() {
/* 低地址 ---> 高地址 */
char str[] = {0X12, 0X34, 0X56, 0X78};
/* 强转为整数后变成 0X78563412 */
int *num = (int *)str;
/* 高地址 <--- 低地址 */
/* int 值: 0X78563412 */
printf("%X\n", *num); /* 打印 78563412 */
}
static void test2() {
if (isLittleEndian() && _isLittleEndian() )
printf("little Endian\n");
else
printf("big Endian\n");
}
static void test3() {
size_t i;
typedef union _Int_ {
unsigned int num;
unsigned char str[4];
} Int;
Int number;
number.num = 0X78563412UL;
for (i = 0; i < sizeof(Int); i++)
printf("%.2X", number.str[i]);
/* 打印结果 12345678 */
printf("\n");
}
static void test4() {
char array[12] = {0X1, 0X2, 0X3, 0X4, 0X5, 0X6, 0X7, 0X8};
short *pshort = (short *)array;
int *pint = (int *)array;
long long *pint64 = (long long *)array;
printf("%#.4X, %#.4X, %#.16llX, %#.8X\n",
*pshort, /* 2字节,输出0X0201 */
*(pshort + 2), /* 前进2步,每步2个字节, 0+4=4,指向 0X05, 0X06, 输出 0X0605 */
*pint64, /* 8字节,输出 0X0807060504030201 */
*(pint + 2)); /* 前进2步, 每步4字节,0+8=8,指向array[8]~array[11],输出00000000 */
}
/************ 测试打印二进制数据 *************/
/*
* showBits
* n: 要展示的数字
* T: 数据类型,char, short, int, long...
* len: 要展示的长度,传入-1则打印全部长度
*/
#define showBits(n, T, len) do { \
char buffer[128] = {'\0'}; \
size_t truc, i, size, spaces, length, bit; \
bit = 1UL; \
truc = len; \
length = 8 * sizeof(T); \
if (truc < length) length = truc; \
spaces = length / 4 - !(length % 4); \
size = length + spaces; \
for (i = 0; i < length && size > 0; i++) { \
if (i && !(i % 4)) buffer[--size] = ' ';\
if (bit&((size_t)n)) buffer[--size] = '1';\
else buffer[--size] = '0'; \
bit <<= 1; \
} \
printf("%s\n", buffer); \
} while(0)
#define showBytes(n, T, len) do { \
size_t i, size = len, mask = 0XFFUL; \
if (size > sizeof(T)) size = sizeof(T); \
for (i = 0; i < size; i++) \
printf("%.2X ", (unsigned char)((n>>(8*(size-1-i)))&mask)); \
printf("\n"); \
} while(0)
static void show_bytes(void *pointer, size_t len) {
size_t i;
unsigned char * ptr = (unsigned char *)pointer;
for (i = 0; i < len; i++)
printf("%.2X ", ptr[len - 1-i]);
printf("\n");
}
/* 测试 size_t 可表示最大容量 */
static void test5() {
size_t n = ~0;
printf("==== test size_t ====\n");
showBits(n, size_t, 8 * sizeof(size_t));
/* 1111 1111 1111 1111 1111 1111 1111 1111 */
#ifdef __x86_64__
printf("%lu bytes\n", n);
printf("%lu kb\n", n / 1024);
printf("%lu M\n", n / 1024 / 1024);
printf("%lu G\n", n / 1024 / 1024 / 1024);
#else
printf("%u bytes\n", n);
printf("%u kb\n", n / 1024);
printf("%u M\n", n / 1024 / 1024);
printf("%u G\n", n / 1024 / 1024 / 1024);
#endif
}
static void test6() {
int len = 15;
char a, b;
a = 8, b = -7;
printf("==== test showBits ====\n");
/* 显示二进制 */
showBits(11, char, -1); /* 0000 1011 */
showBits(14, short, len); /* 000 0000 0000 1110 */
showBits(15, int, len); /* 000 0000 0000 1111 */
showBits(-8, char, len); /* 1111 1000 */
showBits(-7, long, -1); /* 1111 1111 1111 1111 1111 1111 1111 1001 */
showBits(&len, int *, -1); /* 1111 1111 1000 0001 1000 0110 1111 1100 */
/* 16进制按字节打印 */
showBytes(-1, char, -1); /* FF */
showBytes(-2, short, len); /* FF FE */
showBytes(-15, int, len); /* FF FF FF F1 */
showBytes(-8, char, len); /* F8 */
showBytes(-7, int, len); /* FF FF FF F9 */
show_bytes(&a, sizeof(a)); /* 08 */
show_bytes(&b, sizeof(b)); /* F9 */
}
int main() {
test1();
test2();
test3();
test4();
test5();
test6();
return 0;
}
关于位操作
最新推荐文章于 2020-08-11 17:34:47 发布