1. 位运算与运算符优先级
知识点:按位与;按位或;按位异或;负数二进制表示.
按位与:相同位都是1,则与为1,若有一个不是1,则与为0. 常用于将整形变量中某些位清0,而其它位保持不变。
按位或:相同位只要一个是1,则或为1.常用于将整形变量中某些位置1,而其它位保持不变。
按位异或:相同位不同则异或为1,相同则异或为0. 常用于将整形变量中某些位取反,而其它位保持不变。
负数二进制表示:负数以其正值的补码形式表示。反码加1称为补码。
1) 在32bit系统中,调用如下函数,func(2^31-3)的值是?
int func(int x) { return x&-x; } 减号优先级高于异或,2^31-3结果为30.
30二进制表示00000000 00000000 00000000 00011110
反码为 11111111 11111111 11111111 11100001
补码为 11111111 11111111 11111111 11100010,这也是-30的二进制表示。所以func(2^31-3)值为2.
2) 以下语句输出是什么?
#include <stdio.h> int main() { unsigned char ui=0x80; printf("0x%x, 0x%x\n", ui, ~ui); printf("0x%x\n", ~ui>>3+1); char i=0x80; printf("0x%x, 0x%x\n", i, ~i); printf("0x%x\n", ~i>>3+1); return 0; } 对unsigned char, char进行~和printf操作,都会进行类型提升。unsigned char提升时,前面全补0. char提升时,若最高位为0,则前面全补0,若最高位为1,则前面全补1.
所以,第一个printf输出0x80, 0xffffff7f。第三个printf输出0xffffff80, 0x7f.
+号的优先级高于>>,>>运算符对于无符号类型左边移出的空位补0,对于有符号类型,左边移出的空位补符号位。所以,第二个printf输出0xfffffff7. 第四个printf输出0x7.
3) 置位操作
#define SETBIT(x, y) (x |= (1<<y))
#define CLEARBIT(x, y) (x &= ~(1 << y))
#define INVERTBIT(x, y) (x ^= ~(1 << y))
#define GETBIT(x, y) ((x & (1 << y)) ? 1 : 0)
2. 判断系统大小端
bool isLittleEndian() { union un { int i; char c; }endian; endian.i = 1; return ((endian.c == 1) ? true : false); }union数据成员共用内存,并且每个数据成员的首地址都是低地址首字节。
i = 1大端存储为0001, 小端存储为1000,如果c为1则为小端系统。
4. union, struct, sizeof
1) 以下程序输出什么(小端系统)?
union { int i; char x[2]; }a; int main() { a.x[0] = 10; a.x[1] = 1; printf("%x, %d", a.i, a.i); return 0; }10a, 266
2) 计算struct, union的sizeof,以下程序输出是什么?
#include <stdio.h> typedef struct st_a { int i; // offset: 0 double d; // offset: 8 float f; // offset: 16 } ST_A; // sizeof: 24 typedef struct st_b { int i; // offset: 0 char arr1[2]; // offset: 4 double d; // offset: 8 short s2; // offset: 16 ST_A st; // offset: 24 char arr2[9]; // offset: 48 } ST_B; // sizeof: 64 typedef struct st_c { short s1; // offset: 0 short s2; // offset: 2 double d; // offset: 8 short s3; // offset: 16 short s4; // offset: 18 ST_B st; // offset: 24 char arr1[9]; // offset: 88 char arr2[2]; // offset: 97 } ST_C; // sizeof: 104 typedef union { char arr[10]; int i; } U_A; typedef union { char c; int arr1[5]; double d; int arr2[3]; } U_B; typedef union { ST_A st; int i; char c; } U_C; typedef union { char c; } U_D; typedef struct st_d { int i; // offset: 0 char c; // offset: 4 U_B un; // offset: 8 char arr[2]; // offset: 32 } ST_D; // sizeof: 40, U_B has double var typedef struct st_e { int i; // offset: 0 char c; // offset: 4 U_D un; // offset: 5 char arr[6]; // offset: 6 } ST_E; // sizeof: 12 typedef struct st_f { char c; } ST_F; int main(void) { printf("%d %d %d %d %d %d\n", sizeof(ST_A), sizeof(ST_B), sizeof(ST_C), sizeof(ST_D), sizeof(ST_E), sizeof(ST_F)); printf("%d %d %d %d\n", sizeof(U_A), sizeof(U_B), sizeof(U_C), sizeof(U_D)); return 0; } - 结构体的第一个数据成员的offset为0,之后的每个数据成员的存储地址从该数据成员类型大小的整数倍开始,例如ST_A.d.
- 结构体中同时包含结构体成员时,则结构体成员的存储地址要从该结构体成员内部最大数据类型大小的整数倍开始,例如ST_B.st. - 同上,结构体中包含union成员时,则union成员的存储地址要从该union成员内部最大数据类型大小的整数倍开始,例如ST_D.un, ST_E.un.
- 在按上面原则对齐的基础上,结构体的总长度,必须还得是内部最大数据类型的整数倍。
- union的长度为union内部最大数据类型大小的整数倍,且大于等于最大的数据成员所占的存储空间。
以上参考http://blog.csdn.net/selinahuiling/article/details/9046403,并做适当改进,感谢原作者。
输出结果:
24 64 104 40 12 1
12 24 24 1