粉丝问答一|关于计算机补码和结构体的两个问题

哈喽,大家好。今天分享下粉丝针对嵌入式软件开发面试知识点总结中的内容提出的两个问题。问题不难,但是容易掉坑里。 而在笔试中,很多大厂都喜欢出这种题目来坑害小伙伴们。所以,大家在笔试前要扎实基础,做题的时候,要看清题目。

问题一

为什么-n=~ (n-1)=~ n+1?

解答

该问题来源于嵌入式软件开发面试知识点总结P141。原问题为:不用除法操作符如何实现两个正整数的除法。

粉丝的疑问在于表达式-n=~ (n-1)=~ n+1 。解决这个问题的核心在于,要知道计算机中是如何存储数值的。

在计算机系统中,数值一律用补码来表示(存储)。主要原因是使用补码可以将符号位和其他位统一处理;同时,减法也可以按加法来处理。另外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。

如何求补码呢?

  1. 正数的补码 与原码相同。 +9的补码是00001001。
  2. 负数的补码 对其原码逐位取反,但符号位除外;然后整个数加1。 -7的原码为10000111,按位取反为11111000,加1可得11111001。所以-7的补码是11111001。

补码表示方式有很多,以上两个例子都是使用8位的2进制来表示的。此外,还有16位2进制补码表示形式,以及32位2进制补码表示形式等。

如何快速求补码?

从最低位开始至找到的第一个1均不变,符号位不变,这之间的各位“求反”(0变1;1变0)。

原码:1010 1001 补码:1101 0111。

举例

下面,我们举个例子验证下上面的等式。假设n = 10,则可以得到下面的各个表达式。

代码语言:javascript
复制
n:10 = 00001010
-n:-10 = 11110110
n-1:9 = 00001001
~(n-1):-10 = 11110110
~n:-11 = 11110101
~n+1 = 11110110

代码验证

算的对不对呢?可以写个代码验证下。

代码语言:javascript
复制
#include <stdlib.h>
#include <stdio.h>

int PrintBinary(int bi,int len){

int i=0;
while(i<len){

int tmp = 1;
//从最左位开始比较,该位是1
if((bi & (tmp<<(len-i-1))) != 0){
printf(" 1 ");
}
else{
printf(" 0 ");
}
i++;
}
printf("\n");
return 0;
}

int main()
{
int n = 10;
printf("n=%d\n",n);
PrintBinary(n,8);
printf("-n=%d\n",-n);
PrintBinary(-n,8);
printf("n-1=%d\n",n-1);
PrintBinary(n-1,8);
printf("~(n-1)=%d\n", (n-1));
PrintBinary(
(n-1),8);
printf("~n=%d\n", ~n);
PrintBinary(~n,8);
printf("~n+1=%d\n", ~n+1);
PrintBinary(~n+1,8);
return 0;
}

结果如下。

代码语言:javascript
复制
n=10
0 0 0 0 1 0 1 0
-n=-10
1 1 1 1 0 1 1 0
n-1=9
0 0 0 0 1 0 0 1
~(n-1)=-10
1 1 1 1 0 1 1 0
~n=-11
1 1 1 1 0 1 0 1
~n+1=-10
1 1 1 1 0 1 1 0

常用的位运算技巧

  1. -n=~ (n-1)=~ n+1
  2. 获取整数n的二进制中最后一个1:n&(-n)或者n&~(n-1)。例如,n=010100,则-n=101100,n&(-n)= 000100。
  3. 去掉整数n的二进制中最后一个1:n&(n-1),如n=010100,n-1=010011,n&(n-1)=010000。

问题二

结构体所占字节数

该问题来源于嵌入式软件开发面试知识点总结P150。原问题为:指针进行强制类型转换后与地址进行加法运算,结果是什么?

代码语言:javascript
复制
struct BBB
{
  long num;
  char *name;
  short int data;
  char ha;
  short ba[5];
}*p;

在32位机器下, sizeof(struct BBB)=24。但是粉丝算的是28。

解答

char

指针变量

short int

int

unsigned int

float

double

long

long long

unsigned long

32位

1

4

2

4

4

4

8

4

8

4

64位

1

8

2

4

4

4

8

8

8

8

这位粉丝估计是把数据类型所占字节数记错了。

对于32位系统:4+4+2+1+(1)+10+(2)=24

对于64位系统:8+8+2+1+(1)+10+(2)=32

括号中的数字,表示的是为了保证4字节对齐需要填充的字节数。

总结

粉丝的提问,在我能力范围内的,我都会回答。有时候,问题不一定能够及时看到。但是,群里大佬也不少,一般都会有人解答的。

因此,我鼓励大家把问题发到交流群里。大家可以互相学习,互相交流。