快捷搜索:

C语言的那些小秘密之volatile

 C语言的那些小秘密之volatile

  volatile的重要性对于搞嵌入式的程序员来说是不言而喻的,对于volatile的了解程度常常被不少公司在招聘嵌入式编程人员面试的时候作为衡量一个应聘者是否合格的参考标准之一,为什么volatile如此的重要呢?这是因为嵌入式的编程人员要经常同中断、底层硬件等打交道,而这些都用到volatile,所以说嵌入式程序员必须要掌握好volatile的使用。

本文引用地址:

  其实就象读者所熟悉的const一样,volatile是一个类型修饰符。在开始讲解volatile之前我们先来讲解下接下来要用到的一个函数,知道如何使用该函数的读者可以跳过该函数的讲解部分。

  原型:int gettimeofday ( struct timeval * tv , struct timezone * tz );

  头文件:#include

  功能:获取当前时间

  返回值:如果成功返回0,失败返回-1,错误代码存于errno中。

  gettimeofday()会把目前的时间用tv所指的结构返回,当地时区的信息则放到tz所指的结构中。

  [cpp] view plaincopytimeval结构定义为:

  struct timeval{

  long tv_sec;

  long tv_usec;

  };

  timezone 结构定义为:

  struct timezone{

  int tz_minuteswest;

  int tz_dsttime;

  };

  先来说说timeval结构体,其中的tv_sec存放的是秒,而tv_usec存放的是微秒。其中的timezone成员变量我们很少使用,在此简单的说说它在gettimeofday()函数中的作用是把当地时区的信息则放到tz所指的结构中,在其中tz_minuteswest变量里存放的是和Greenwich 时间差了多少分钟,tz_dsttime日光节约时间的状态。我们在此主要的是关注前一个成员变量timeval,后一个我们在此不使用,所以使用gettimeofday()函数的时候我们把有一个参数设定为NULL,下面先来看看一段简单的代码。

  [cpp] view plaincopy#include

  #include

  int main(int argc, char * argv[])

  {

  struct timeval start,end;

  gettimeofday( &start, NULL ); /*测试起始时间*/

  double timeuse;

  int j;

  for(j=0;j<1000000;j++)

  ;

  gettimeofday( &end, NULL ); /*测试终止时间*/

  timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_sec - start.tv_sec ;

  timeuse /= 1000000;

  printf("运行时间为:%f\n",timeuse);

  return 0;

  }

  运行结果为:

  [cpp] view plaincopyroot@ubuntu:/home# ./p

  运行时间为:0.002736

  现在来简单的分析下代码,通过end.tv_sec - start.tv_sec 我们得到了终止时间跟起始时间以秒为单位的时间间隔,然后使用end.tv_sec - start.tv_sec 得到终止时间跟起始时间以微妙为单位的时间间隔。因为时间单位的原因,所以我们在此对于( end.tv_sec - start.tv_sec ) 得到的结果乘以1000000转换为微秒进行计算,之后再使用timeuse /= 1000000;将其转换为秒。现在了解了如何通过gettimeofday()函数来测试start到end代码之间的运行时间,那么我们现在接下来看看volatile修饰符。

  通常在代码中我们为了防止一个变量在意想不到的情况下被改变,我们会将变量定义为volatile,这从而就使得编译器就不会自作主张的去“动”这个变量的值了。准确点说就是每次在用到这个变量时必须每次都重新从内存中直接读取这个变量的值,而不是使用保存在寄存器里的备份。

  在举例之前我们先大概的说下Debug和Release 模式下编译方式的区别,Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。大致的知道了Debug和Release的区别之后,我们下面来看看一段代码。

  [cpp] view plaincopy#include

  void main()

  {

  int a=12;

  printf("a的值为:%d\n",a);

  __asm {mov dword ptr [ebp-4], 0h}

  int b = a;

  printf("b的值为:%d\n",b);

  }

  先分析下上面的代码,我们使用了一句__asm {mov dword ptr [ebp-4], 0h}来修改变量a在内存中的值,如果有对这句代码功能不清楚的读者可以参考我之前的一篇《C语言的那些小秘密之堆栈》,在此就不做过多的讲解了。前面已经讲解了Debug和Release 编译方式的区别,那么我们现在来对比看下结果。注:使用vc6编译运行,如无特殊说明,均在linux环境下编译运行。读者自己在编译的时候别忘了选择编译运行的模式。

  使用Debug模式的结果为:

  [cpp] view plaincopya的值为:12

  b的值为:0

  Press any key to continue

  使用Release模式的结果为:

  [cpp] view plaincopya的值为:12

  b的值为:12

  Press any key to continue

您可能还会对下面的文章感兴趣: