背景
今天面试了一家公司,面试官问了我一个开放性的问题。大致意思是,为什么对volatile修饰的变量调用memset函数,编译的时候会报错。当然,我是不知道为什么啦。之前没有遇到过嘛。不过我还是做了一点分析,我认为问题出在memset函数的实现上。一般情况下volatile关键字修饰的变量在编译的时候会取消编译优化,即每次使用变量时都会访问变量对应的地址,而不是将变量读入寄存器中连续使用。
探索
面试结束后,我写了个简单的代码测试了一下。大致如下
#include <stdio.h>
int main(void)
{
volatile int a;
memset(&a,0,sizeof(int));
}
编译出现了一个警告
warning: passing argument 1 of ‘memset’ discards ‘volatile’ qualifier from pointer target type
我的理解是这个volatile变量传入函数后volatile的特性会被丢掉。
为了研究为什么会这样,接下来我阅读了linux内核中memset的源码。
void *memset(void *pdst, int c, unsigned int plen)
{
/* Now we want the parameters in special registers. Make sure the
compiler does something usable with this. */
register char *return_dst __asm__ ("r10") = pdst;
register int n __asm__ ("r12") = plen;
register int lc __asm__ ("r11") = c;
.....
}
上面这部分源码解答了我的疑惑,原来memset在执行过程中,强制把传入的地址放入了r10寄存器,之后也会直接通过连续操作寄存器来访问变量,这里就和volatile每次都要读取物理地址而不能连续使用寄存器内容的特性冲突了。