1、编写一个简单函数检查处理器是 big-endian 还是 little-endian。
定义:
little-endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;
big-endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端;
网络字节序 TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
思路:
由于联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little- endian还是Big-endian模式读写。
1 #include <stdio.h>
2
3 int main(void) 4 { 5 union MyUnion 6 { 7 unsigned int a; 8 unsigned char b; 9 }; 10
11 union MyUnion test; 12 test.a = 1; 13 printf("%d\n", test.b);//1:little-endian 0:big-endian
14
15 return 0; 16 }
如上图,我的处理器是 little-endian。
2、假设 x = 9999,求下面函数的返回值。—— 微软
1 int func(x) 2 { 3 int countx =0; 4 while (x) 5 { 6 countx++; 7 x = x & (x - 1); 8 } 9 return countx; 10 }
思路:将 x 转换为二进制表示,看其中1的个数。如 x = 9999 = 0B0010 0111 0000 1111(对于二进制数前缀0B,有的编译器可能会出错),其中有8个1,则函数返回值 countx=8。
原理:每执行一次 x = x & (x - 1),会将 x 用二进制表示时最右边的一个1变为0,因为 x - 1 将会将该位(x用二进制表示时最右边的一个1)变为0。
1 #include <stdio.h> 2 3 int func(int x); 4 5 int main(void) 6 { 7 int x; 8 9 printf("please enter a integer(>0):"); 10 if ((1 == (scanf("%d", &x))) && (x > 0)) 11 printf("%d\n",func(x)); 12 else 13 printf("please enter a integer(>0)\n"); 14 15 return 0; 16 } 17 18 int func(int x) 19 { 20 int countx = 0; 21 while (x) 22 { 23 countx++; 24 x = x & (x - 1); 25 } 26 return countx; 27 }
验证代码如上,如键入9999,结果如下:
3、请编写一个简单的函数判断一个数是否是2的n次方。
思路:如果一个整数是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0。此题转变为判断一个整数用二进制数表示时最高位是否为1,用 (x = x & (x - 1)) == 0可判断,此题与例2均为巧用 x = x & (x - 1)。
1 #include <stdio.h> 2 3 void func(int x); 4 5 int main(void) 6 { 7 int x; 8 9 printf("please enter a integer(>=0):"); 10 if (1 == scanf("%d", &x)) 11 func(x); 12 else 13 printf("please ensure it's a integer.\n"); 14 15 return 0; 16 } 17 18 void func(int x) 19 { 20 if (0 == (x = x & (x - 1))) 21 printf("Yes.\n"); 22 else 23 printf("No.\n"); 24 }
4、下面关于“联合”的程序的输出是什么?
1 #include <stdio.h> 2 3 union 4 { 5 int i; 6 char x[2]; 7 }a; 8 9 void main(void) 10 { 11 a.x[0] = 10; 12 a.x[1] = 1; 13 printf("%d\n", a.i); 14 }
思路:整型变量 i 和 char 型数组共享一个内存地址。值以数组形式存入,以整型变量读出。
注意:x[0]内存低地址,x[1]内存高地址。当处理器为 little-endian 时,以整型变量读出为 0X010A;当处理器为 big-endian 时,以整型变量读出为 0X0A01。
我的PC处理器为 little-endian ,所以程序输出为 0X010A,即266。
5、下面关于“联合”的程序的输出是什么?
1 #include <stdio.h> 2 3 int main(void) 4 { 5 union 6 { 7 int i; 8 struct 9 { 10 char first; 11 char second; 12 }half; 13 }number; 14 15 number.i = 0x4241; 16 printf("%c%c\n", number.half.first, number.half.second); 17 18 number.half.first = 'a'; 19 number.half.second = 'b'; 20 printf("%x\n", number.i); 21 22 return 0; 23 }
思路:1、联合体中各成员共享一块内存(内存地址相同),故整型变量 i 与结构体 half 内存地址相同;
2、程序中动态变量存放在栈中,先定义先分配内存。对于单字节数据,很好理解;对于多字节数据,存在处理器是 big-endian 还是 little-endian 的问题。big-endian 的处理器存储时将多字节的高位放在低地址,低位放在高地址,读出时也将低地址的字节认为是高位,高地址的字节认为是高位;little-endian 的处理器存储时将多字节的高位放在高地址,低位放在低地址,读出时将低地址的字节认为是低位,高地址的字节认为是高位。
3、我的PC处理器是 little-endian,故四字节 i 的高位放置在高地址、低位放置在低地址,number.half.first 对应 i 的低地址,number.half.second 对应 i 的次低地址。
number.i = 0x4241,则 number.half.first = 0x41 = 'A' ; number.half.second = 0x42 = 'B' ; printf语句打印出 AB
number.half.first = 'a', number.half.second = 'b', 则 i 的低地址存储 ‘a’ = 97 = 0x61, i 的次低地址存储 'b' = 98 = 0x62; i 的高位及次高位为 0x0000; printf 语句打印出6261,需要打印出 0x 则需要使用 %#x 格式控制符。