雄安新区网站建设,昆明市网站推广,wordpress 左边栏,二级域名租用一次难忘的面试经历多年前#xff0c;一次互联网某厂实习生的面试题#xff0c;题目的代码片段很简单#xff0c;如下#xff1a;1 #include 2 int main()3 {4 int *restrict pInt (int*)malloc(4);5 int *pNewInt pInt;6 return 0;7 }
12345678面试官问… 一次难忘的面试经历多年前一次互联网某厂实习生的面试题题目的代码片段很简单如下 1 #include 2 int main()3 {4 int *restrict pInt (int*)malloc(4);5 int *pNewInt pInt;6 return 0;7 }
12345678
面试官问我运行结果是什么我居然当时不加思索的回答编译器会报错。当时个人理解是这样的首先用malloc函数分配了一个4Bytes大小的内存并让pInt指针指向它。同时pInt指针也被restrict关键字修饰。而restrict就是用来表明是访问一个数据对象的唯一且初始的方式。因此在第5行中将pInt的值赋值给了另一个指针pNewInt就是错误的。但是遗憾的是这种错误编译器是不会报错的。下面我们就这个问题来聊一聊restrict关键字。不使用restrict关键字restrict关键字实际上在C99标准出来以前编译器就已经开始支持类似restrict的语句了如编译器定义了__restrict。restrict关键字实际上是用来指示编译器对代码进行优化的。在分析具体含义以前我们先来看一个没有用restrict的例子。在main函数中定义了三个参数p、q、r。这之后调用了f函数并把p和q的地址传递进去。在f中根据这两个地址将p和q分别设置为2和3最后把p的值2当做函数返回值返回并赋值给整形变量r。这个代码很简单不过重点不是看它而是它的反汇编代码下面我们通过objdump工具执行objdump -j .text -l -C -S test来生成汇编代码。 首先来看下main函数的汇编代码。如下图所示在反汇编代码中的可以看到分别将p和q的地址分别赋值给了rdi和 rsi寄存器。即rdi保存了p的地址rsi保存了q的地址。之后调用了f函数。而在f函数的反汇编代码中通过如下图所示能确认rdi确实保存着p的地址 接着如下图所示可以看到通过调用了puts函数向屏幕打印信息最后f函数最后用rax所指向区域的值赋给了eax寄存器即将p的值放入eax作为返回值返回。好了现在有一个疑问代码其对应的反汇编代码干嘛不直接把立即数2直接赋值给eax,反而多此一举从rax所指向的内存中把2取出来给eax呢因为编译器之所以不直接把2赋值给eax,而非要从内存中获取就是担心代码中会通过其他指针访问p所占的区域。在test.c的代码中我们通过指针a访问了p所占的区域但是编译器不知道指针b是否也是指向p所占的区域通过指针b是否也对该区域做了修改。因此编译器只能根据return *a从内存中将2取出来赋值给eax。使用restrict关键字好了怎么样才能让编译器变得聪明一点呢这个时候restrict就派上用场了。修改上面代码 运行编译命令gcc -g -O2 -stdc99 -o test test.c进行编译使用反汇编工具objdump查看发现可以看到直接把2赋给了eax寄存器作为f的返回值返回了。看明白了吧restrict关键字起作用了编译器检测到指针a和b都使用了restrict关键字也就是说它们所指向的空间都只能通过指针a和b访问不会有其他途径。这个时候编译器就可以放心大胆地进行优化了直接把2赋给了eax,而不用再从内存中获取了。这样f的执行效率也提高了。这里还有一点需要注意C 程序并不支持restrict关键字但是可以使用“__restrict”关键字。