当前位置:文档之家› c语言中volatile关键字是什么含义

c语言中volatile关键字是什么含义

c语言中volatile关键字是什么含义
c语言中volatile关键字是什么含义

c语言中volatile关键字是什么含义

最佳答案volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。

例如:

volatile int i=10;

int j = i;

...

int k = i;

volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。

而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。

1.请问TCP/IP协议分为哪几层?FTP协议在哪一层?

答:

TCP/IP整体构架概述

OSI的七层参考模型:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为:

应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。

传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。

互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。

网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据

2\已知strcpy 函数的原型是 char *strcpy(char *strDest, const char *strSrc); 其中strDest 是目的字符串,strSrc 是源字符串。 (1)不调用C++/C 的字符串库函数,请编写函数strcpy (2)strcpy 能把strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?#include

#include

char* StrCpy(char *strDest, const char *strSrc)

{

if(!strDest||!strSrc)

return NULL;

if (!strlen(strSrc))

{

*strDest='\0';

return strDest;

}

char* tmp=strDest;

do

{

*tmp++=*strSrc;

} while (*strSrc++);

return strDest;

}

int main()

{

char str1[20],str2[20];

scanf("%s",str2);

printf("%s\n",StrCpy(str1,str2));//这一行就说明了返回char*的作用

return 0;

}

2.C语言中static函数与普通函数的区别是什么?

答:1.static有什么用途?(请至少说明两种)

1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。

2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。

3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用

static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用; static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

telnet在Tcp/Ip协议中是什么意思?

Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法SNMP的基本功能是:取得,设置和接收代理发送的意外信息。取得指的是基站发送请求,代理根据这个请求回送相应的数据,设置是基站设置管理对象(也就是代理)的值,接收收代理发送的意外信息是指代理可以在基站未请求的状态下向基站报告发生的意外情况。

同步方式Mutex和Cirtical Section的区别

E vent分自动和手动两种,手动Event得到信号时,所有等待该事件的线程都将进入可调度

状态,自动Event得到信号时,只有一个等待该事件的线程进入可调度状态。

Mutex每次只有一个线程得到信号,Mutex的内部维护一个线程id,用于标识系统中的哪个线程当前拥有该Mutex对象,与其他的内和对象不同即使Mutex处于没有信号的状态,只要

该线程的ID与Mutex维护的ID相同,该线程就可以保持可调度状态。

Semaphore不同于其他内核对象的的地方是他有一个可用资源计数的功能。

Critical Section不同于前面所提到的三种,他们都是内核对象,是在内核方式下实现同步的,而Critical Section则是在用户方式下实现的同步的,效率比前面的三种都要高;另外Critical Section是不能跨进程使用的。

3、

事件(Event)是WIN32提供的最灵活的线程间的同步方式,事件可处于激发状态或未激发状态。根据状态变迁方式的不同,事件分为手动设置和自动恢复两类。

互斥量(Mutex)跟临界区很相似,只有拥有胡扯对象的线程才具有访问资源的权限。互斥量又比临界区复杂,运行速度也比较慢,因为使用互斥量不仅能够在同一个应用程序不同线程中实现资源的安全共享,还可以在不同应用程序的线程间实现对资源的安全共享。

信号量(Senmaphores)对象对线程的同步方式与前面几种方法不同,信号量允许多个线程同时使用共享资源。信号量的值我们可以认为是可以同时访问贡献资源的线程最大数目,或者可以理解为可以共享使用的某一类资源的数目。

临界区(CriticalSection)在任意时刻只允许一个线程对共享资源进行访问。临界区不是OS核心对象,如果进入理解去的线程“挂”了,将无法释放临界资源,这个缺点在互斥量中得到了弥补,因为使用互斥量可以设置超时值。

静态-全局静态函数(或变量)和类的静态成员函数(或变量)Static关键字

用来声明静态函数或者静态变量。

静态函数:用static声明的函数是静态函数。静态函数可以分为全局静态函数和类的静态成员函数。

静态变量:用static声明的变量是静态变量。静态变量可以分为全局静态变量和类的静态成员变量。

在类中,用static声明的变量为类的静态成员变量,它为该类的公用变量,对于该类的所有对象来说,static成员变量只有一份。在类中,用static声明的函数是类的静态成员函数,在调用该函数时,不会将对象的引用(this 指针)传递给它,所以在静态函数中不可访问非静态的成员函数或者非静态的成员变量(访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问。)。可以通过对象引用或类名(不需要实例化)访问静态成员函数或者静态成员变量。静态类成员的特性就是属于类而不专属于某一个对象。类中的任何成员函数都可以访问静态成员,但静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员,因为静态成员函数没有this 指针。---所以构造函数不可以定义为static(构造函数中要初始化普通成员变量和构造对象)。

C|C 中的静态全局变量,静态局部变量,全局变量,局部变量的区别C|C++中的静态全局变量,静态局部变量,全局变量,局部变量的区别。从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间全局变量

本身就是静态存储方式,静态全局变量当然也是静态存储方式。静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

C 语言中什么是“句柄”和“指针”

所谓句柄实际上是一个数据,是一个Long (整长型)的数据。

句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,,句柄是一个标识符,是拿来标识对象或者项目的,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。

为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows

内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。

telnet在Tcp/Ip协议中是什么意思

Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序

,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,

就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet

会话,

必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法

SNMP的基本功能是:取得,设置和接收代理发送的意外信息。取得指的是基站发送请求,代理根据这个请求回送相应的数据,设置是基站设置管理对象(也就是代理)的值,接收收代理发送的意外信息是指代理可以在基站未请求的状态下向基站报告发生的意外情况。

内存中堆(heap)和栈(stack)的区别(非数据结构中的堆和栈)

在进行C/C++编程时,需要程序员对内存的了解比较精准。经常需要操作的内存可分为以下几个类别:

二、1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束后有系统释放

4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放

5、程序代码区—存放函数体的二进制代码。

C++面向对象与面向过程的对比

最主要的区别是模块,而模块化的基础就是封装。C++把有独立功能的代码块封装到一个类中,避免了重复开发,可以有效的节省开发时间,这就是C++最大的优点。但是,由于对代码进行了封装,所以一些底层操作也就不再透明,你只能看到功能,而看不到这个功能是如何实现的。如果是做windows应用程序软件开发,肯定要用面向对象的方法,微软自带的MFC类库给我提供了各种封装好的类供用户使用,大大缩减开发周期。

当然面向对象开发的语言很多,java也是其中比较强大的语言,而且似乎比C++的开发周期更短。

TCP协议的作用和IP协议的作用有什么不同

ip协议工作在OSI模型的网络层,在数据包里面帧封装后面就是IP封装,IP是IP网络的基础,同样的还有IPX,APPLETALK等协议,TCP工作在IP的上一层,统UDP一样,在数据包里面IP报头后面就是TCP或者UDP的包头,当然前提是相应的应用得用他们

路由器和交换机的区别

交换机是一种基于MAC(网卡的硬件地址)识别,能完成封装转发数据包功能的网络设备。交换机可以“学习”MAC地址,并把其存放在内部地址表中,通过在数据帧的始发者和目标接收者之间建立临时的交换路径,使数据帧直接由源地址到达目的地址。

交换机主要是组成局域网,例如一个公司网络的搭建一般是使用交换机的,交换机不能转发数据包,也没有路由到目的地址.

现在交换机也分为二层交换机和三层交换机,三层交换机具有了路由器的功能了.

路由器可以说是组成广域网的一个重要部分,路由器就是为数据包找到最合适的到达路径的.

就路由器与交换机来说,主要区别体现在以下几个方面:

(1)工作层次不同最初的的交换机是工作在OSI/RM开放体系结构的数据链路层,也就是第二层,而路由器一开始就设计工作在OSI模型的网络层。由于交换机工作在OSI 的第二层(数据链路层),所以它的工作原理比较简单,而路由器工作在OSI的第三层(网络层),可以得到更多的协议信息,路由器可以做出更加智能的转发决策。

(2)数据转发所依据的对象不同交换机是利用物理地址或者说MAC地址来确定转发数据的目的地址。而路由器则是利用不同网络的ID号(即IP地址)来确定数据转发的地址。IP地址是在软件中实现的,描述的是设备所在的网络,有时这些第三层的地址也称为协议地址或者网络地址。MAC地址通常是硬件自带的,由网卡生产商来分配的,而且已经固化

到了网卡中去,一般来说是不可更改的。而IP地址则通常由网络管理员或系统自动分配。(3)传统的交换机只能分割冲突域,不能分割广播域;而路由器可以分割广播域由交换机连接的网段仍属于同一个广播域,广播数据包会在交换机连接的所有网段上传播,在某些情况下会导致通信拥挤和安全漏洞。连接到路由器上的网段会被分配成不同的广播域,广播数据不会穿过路由器。虽然第三层以上交换机具有VLAN功能,也可以分割广播域,但是各子广播域之间是不能通信交流的,它们之间的交流仍然需要路由器。

(4)路由器提供了防火墙的服务路由器仅仅转发特定地址的数据包,不传送不支持路由协议的数据包传送和未知目标网络数据包的传送,从而可以防止广播风暴。如果你对网络不太了解上面这些比较专业的知识很难看到. 最通俗的语言就是,交换机负责同一网段的通信,路由器负责不同网段的通信.

ping是使用TCP/IP协议中的什么协议?

使用的是ICMP协议,是“Internet Control Message Protocol”(Internet控制消息协议)的缩写,是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。strlen与sizeof的区别

1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。

该类型保证能容纳实现所建立的最大对象的字节大小。

2.sizeof是算符,strlen是函数。

3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。

4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。

5.大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度这就是sizeof(x)可以

用来定义数组维数的原因

char str[20]="0123456789";//str是编译期大小已经固定的数组

int a=strlen(str); //a=10;//strlen()在运行起确定

int b=sizeof(str); //而b=20;//sizeof()在编译期确定

6.strlen的结果要在运行的时候才能计算出来,是用来计算字符串的实际长度,不是类型占内存的大

小。

7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是

个函数。

char c;

sizeof c;//变量名可以不加括弧

8.当适用了于一个结构类型时或变量,sizeof 返回实际的大小,

当适用一静态地空间数组,sizeof 归还全部数组的尺寸。

sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸

内联函数与宏定义的差别

内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接呗镶嵌到目标代码中。

内联函数要做参数类型检查,这是内联函数跟宏相比的优势。

inline是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到那里去。对于短小的代码来说,inline可以带来一定的效率提升,

而且和C时代的宏函数相比,inline更安全可靠。可是这个是以增加空间消耗为代价的。至于是否需要inline函数就需要根据你的实际情况取舍了。

inline一般只用于如下情况:

(1)一个函数不断被重复调用。

(2)函数只有简单的几行,且函数不包含for、while、switch语句。

●一般来说,我们写小程序没有必要定义成inline,但是如果要完成一个工程项目,当一个简单函数被调用多次时,则应该考虑用inline。

宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少了普通函数调用时的资源消耗。

宏不是函数,只是在编译前(编译预处理阶段)将程序中有关字符串替换成宏体。

inline函数是函数,但在编译中不单独产生代码,而是将有关代码嵌入到调用处。

c语言中#和##的用法

本文主要讲述c语言的一点基础语法和在内核的应用中其中的一点例子。 #,##分别在c语言中是怎么作用? 文章代码编译的环境: 桌面环境:Ubuntu10.04 内核:linux2.6.32 编译器:gcc4.4.3 一、基本的用法 1、#.参数名以#作为前缀则结果将被扩展为由实际参数的带引号的字符串。如: #define dprint(expr)printf(#expr"=%d\n",expr); intmain() { inta=20,b=10; dprint(a/b); return0; } 上面的例子会打印出: a/b=2 2、##.预处理器运算符##为宏提供了一种连接实际参数的手段。如果替换文本中的参数与##相邻,则该参数将被实际参数替换,##与前后的空白将被删除,并对替换后的结果重新扫描。 形成一个新的标号,如果这样产生的记号无效,或者结果依赖于##运算顺序,则结果没有定义。 如: #definepaste(front,back)front##back 因此,宏调用paste(name,_xiaobai)的结果为name_xiaobai. 如: #define createfun(name1,name2)\ void name1##name2()\ {\ printf("%scalled\n",__FUNCTION__);\ } createfun(the,function); intmain() { thefunction(); return0; } 输出的结果是:thefunctioncalled 二、##可以嵌套吗?

看下面的例子: #define cat(x,y)x##y 宏调用cat(var,123)讲生成var123. 但是,宏调用cat(cat(1,2),3)没有定义:##阻止了外层调用的参数的扩展。因此,它将生成下列的记号串: cat(1,2)3. 如果要再引入第二层的宏定义,如下定义: #define xcat(x,y)cat(x,y) 那么xcat(xcat(1,2),3)将生成123, 这是因为xcat自身的扩展不包含##运算符。 三、linux内核中例子 因为是做mips架构的,所以以mips为例子。 Linux2.6.25内核,include/asm-mips/io.h文件。拷贝一部分的代码出来。 #define__BUILD_MEMORY_SINGLE(pfx,bwlq,type,irq)\ \ staticinlinevoidpfx##write##bwlq(typeval,\ volatilevoid__iomem*mem)\ {\ volatiletype*__mem;\ type__val;\ \

C语言中的32个关键字及其意思

由ANSI标准定义的C语言关键字共32个: auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if while static 一、数据类型关键字(12个): 1、char [t?ɑ:]:声明字符型变量或函数 (1)主要内容字符:容纳单字符的一种基本数据类型;(2)n.炭;女清洁工 vt. 烧焦; (3)字符类型:字符型(Char) c、字符串型(String) s 、二进制型(Binary) bn、布尔型(Boolean) b 、日期时间型(DateTime) d 、数组型(Array) a、象型(Object) o 、循环控制变量通常使用单一的字符; 2、double [?d?b?l] :声明双精度变量或函数 (1)n. 两倍;(2)a. 两倍的,双重的;(3)v. 加倍的,快步走,加倍努力 3、enum :声明枚举类型 (1)枚举:枚举是一个被命名的整型常数的;(2)枚举类型;(3)列举型; (4)列举enumerate [i?nju:m?reit] 4、float [fl?ut] :声明浮点型变量或函数 (1)浮点数、(2)浮点型、(3)漂浮、(4)浮动 5、int[int]:声明整型变量或函数 (1)符号整数、(2)取整、(3)Int是 integer ['intid??] 的简写 int 声明一个变量为整型。占2个字节,最大表示范围:-32768到32767(十进制)。 long 声明一个变量为长整型。长整型变量占4个字节,最大表示范围: -2147483648(十进制)到2147483647(十进制)。 6、long [l??] :声明长整型变量或函数 (1)长整型(2)a./ ad.长(期)的(地)(3) n.长时间(4)vi.渴望 7、short [??:t] :声明短整型变量或函数 (1)a. 短的,矮的、(2)n. 短裤、(3)adv. 短暂地;突然地,急地 8、signed:声明有符号类型变量或函数 (1)有符号的、(2)带正负号、(3)sign [sain] n.标记,符号;招牌;迹象 v.签(署) 9、struct:声明结构体变量或函数 (1)n.结构(2)结构体(4)创建构架数组(3)structural[?str?kt??r?l]a. 结构的 10、union [?ju:ni?n]:声明共用体(联合)数据类型 (1)联合、(2)n.工会,联盟、(3)合并、(4)团结 11、unsigned [?n'saind]:声明无符号类型变量或函数 (1)无符号的 (1)无符号的 12、void [v?id] :声明函数无返回值或无参数,声明无类型指针(基本上就 这三个作用) (1)a.无效的、(2)没有的、(3)vt.使无效、(4)n.空虚感 二、控制语句关键字(12个):

C语言中volatile用法小结

计算机二级C技巧:c语言中的volatile关键字 来源:考试大 2009年06月10日10:36 volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。 用volatile关键字声明的变量i每一次被访问时,执行部件都会从i相应的内存单元中取出i的值。 没有用volatile关键字声明的变量i在被访问的时候可能直接从cpu的寄存器中取值(因为之前i被访问过,也就是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快的多)。 以上两种情况的区别在于被编译成汇编代码之后,两者是不一样的。之所以这样做是因为变量i可能会经常变化,保证对特殊地址的稳定访问。 volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 使用该关键字的例子如下: int volatile nVint; 当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 例如: volatile int i=10; int a = i; ... //其他代码,并未明确告诉编译器,对i进行过操作 int b = i; volatile 指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。 注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无volatile关键字,对程序最终代码的影响: 首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的代码:#i nclude void main() { int i=10; int a = i; printf("i= %d\n",a); //下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道

c语言中#和##的用法

本文主要讲述c语言的一点基础语法与在内核的应用中其中的一点例子。 #,##分别在c语言中就是怎么作用? 文章代码编译的环境: 桌面环境:Ubuntu10、04 内核:linux2、6、32 编译器:gcc4、4、3 一、基本的用法 1、#、参数名以#作为前缀则结果将被扩展为由实际参数的带引号的字符串。如: #define dprint(expr)printf(#expr"=%d\n",expr); intmain() { inta=20,b=10; dprint(a/b); return0; } 上面的例子会打印出: a/b=2 2、##、预处理器运算符##为宏提供了一种连接实际参数的手段。如果替换文本中的参数与##相邻,则该参数将被实际参数替换,##与前后的空白将被删除,并对替换后的结果重新扫描。 形成一个新的标号,如果这样产生的记号无效,或者结果依赖于##运算顺序,则结果没有定义。 如: #definepaste(front,back)front##back 因此,宏调用paste(name,_xiaobai)的结果为name_xiaobai、 如: #define createfun(name1,name2)\ void name1##name2()\ {\ printf("%scalled\n",__FUNCTION__);\ } createfun(the,function); intmain() { thefunction(); return0; } 输出的结果就是:thefunctioncalled 二、##可以嵌套不? 瞧下面的例子: #define cat(x,y)x##y

C语言复习资料

C语言复习 第一章 所谓程序,就是一组计算机能识别和执行的指令。 只要让计算机执行这个程序,计算机就会“自动地”执行各条指令,有条不紊地进行工作。 计算机的一切操作都是由程序控制的,离开程序,计算机将一事无成。 一种计算机和人都能识别的语言,这就是计算机语言。 机器语言(低级)由0和1组成的指令。 符号语言(低级)用一些英文字母和数字表示一个指令。 高级语言接近于人们习惯使用的自然语言和数学语言。第一个计算机高级语言是FORTRAN语言。 非结构化的语言,结构化语言都是面向过程的语言,如 BASIC,FORTRAN,ALGOL;QBASIC,FORTRAN77,C. 面向对象的语言,C++,C#,Visual Basic和Java等语言。 C语言是国际上广泛流行的计算机高级语言。 C语言的祖先是BCPL语言。然后发展为B语言,这两者的特点是精炼,接近硬件,但是过于简单,无数据类型。C语言是在B语言的基础上设计出来的。 C语言是一种用途广泛、功能强大、使用灵活的过程性编程语言,既可以用于编写应用软件,又能用于编写系统软件。 C语言的主要特点: 1.语言简洁、紧凑、,使用灵活、方便。 2.运算符丰富。 3.数据类型丰富。 4.具有结构化的控制语句。 5.语法限制不太严格,程序设计自由度大。

6.C语言允许直接访问物理地址,能进行位(bit)操作,能实现汇编语言的大 部分功能,可以直接对硬件进行操作。 7.用C语言编写的程序可移植性好。 8.声称目标代码质量高,程序执行效率高。 每一个C语言程序都必须有一个main函数。 //表示到本行结束是“注释”。 在编译时注释部分不产生目标代码,注释对运行不起作用。注释只是给人看的,而不是计算机执行的。 两种注释: 1.以//开始的单行注释,可单独占一行,也可出现在其他内容右侧,注释部分从// 开始,以换行符结束,不能跨行。可以使用多个单行注释。 2.以/*开始,以*/结束的块式注释。这种注释可包含多行内容。编译系统发现一个 /*后会开始找注释结束符*/,把二者之间的内容作为注释。 注意:在字符串中的//和/*不作为注释的开始,而是作为字符串的一部分。如: printf(”//how do you do!\n”); 或 printf(“/*how doyou do!*/\n”); 输出分别是: //how do you do! 和 /*how do youdo!*/ 注释可以用汉字或英文字符表示。 C89只允许使用/**/形式的注释。 C语言程序的结构有以下特点: 1.一个程序由一个或多个源程序文件组成,源程序文件中可以包括三个部分:预处理 指令,全局声明,函数定义。 2.函数是C程序的主要组成部分,函数是C程序的基本单位。

C语言中auto,register,static,const,volatile的区别

C语言中auto,register,static,const,volatile的区别 (1)auto 这个关键字用于声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。这个关键字不怎么多写,因为所有的变量默认就是auto的。 (2)register 这个关键字命令编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率。 (3)static 常见的两种用途: 1>统计函数被调用的次数; 2>减少局部数组建立和赋值的开销.变量的建立和赋值是需要一定的处理器开销的,特别是数组等含有较多元素的存储类型。在一些含有较多的变量并且被经常调用的函数中,可以将一些数组声明为static类型,以减少建立或者初始化这些变量的开销. 详细说明: 1>、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与栈变量和堆变量的区别。 2>、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。 3>当static用来修饰全局变量时,它就改变了全局变量的作用域,使其不能被别的程序extern,限制在了当前文件里,但是没有改变其存放位置,还是在全局静态储存区。 使用注意: 1>若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度; 2>若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度; 3>设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题(只要输入数据相同就应产生相同的输出)。 (4)const 被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。它可以修饰函数的参数、返回值,甚至函数的定义体。 作用: 1>修饰输入参数 a.对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const引用传递”,目的是提高效率。例如将void Func(A a) 改为void Func(const A &a)。 b.对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。 2>用const修饰函数的返回值 a.如果给以“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同类型指针。 如对于:const char * GetString(void); 如下语句将出现编译错误: char *str = GetString();//cannot convert from 'const char *' to 'char *'; 正确的用法是:

c语言中volatile关键字

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。 用volatile关键字声明的变量i每一次被访问时,执行部件都会从i相应的内存单元中取出i 的值。 没有用volatile关键字声明的变量i在被访问的时候可能直接从cpu的寄存器中取值(因为之前i被访问过,也就是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快的多)。 以上两种情况的区别在于被编译成汇编代码之后,两者是不一样的。之所以这样做是因为变量i可能会经常变化,保证对特殊地址的稳定访问。 =====以下为转载====== volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改 ,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的 代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 使用该关键字的例子如下: int volatile nVint; 当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即 使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 例如: volatile int i=10; int a = i; ... //其他代码,并未明确告诉编译器,对i进行过操作 int b = i; volatile 指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编 译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新 从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说vola tile可以保证对特殊地址的稳定访问。 注意,在vc6中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面 通过插入汇编代码,测试有无volatile关键字,对程序最终代码的影响: 首先,用classwizard建一个win32 console工程,插入一个voltest.cpp文件,输入下面的 代码: #i nclude

嵌入式C语言中必须的关键字

1.static关键字 这个关键字前面也有提到,它的作用是强大的。 要对static关键字深入了解,首先需要掌握标准C程序的组成。 标准C程序一直由下列部分组成: 1)正文段——CPU执行的机器指令部分,也就是你的程序。一个程序只有一个副本;只读,这是为了防止程序由于意外事故而修改自身指令; 2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放在这里。 3)非初始化数据段(bss段)——在程序中没有初始化的全局变量;内核将此段初始化为0。 注意:只有全局变量被分配到数据段中。 4)栈——增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。这句很关键,常常有笔试题会问到什么东西放到栈里面就足以说明。 5)堆——动态存储分配。 在嵌入式C语言当中,它有三个作用: 作用一:在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 这样定义的变量称为局部静态变量:在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。也就是上面的作用一中提到的在函数体内定义的变量。除了类型符外,若不加其它关键字修饰,默认都是局部变量。比如以下代码: void test1(void) { unsigned char a; static unsigned char b; … a++; b++; } 在这个例子中,变量a是局部变量,变量b为局部静态变量。作用一说明了局部静态变量b的特性:在函数体,一个被声明为静态的变量(也就是局部静态变量)在这一函数被调用过程中维持其值不变。这句话什么意思呢?若是连续两次调用上面的函数test1: void main(void) { … test1(); test1(); … }

C语言中的volatile关键字用法大全

C语言中的volatile关键字 2008-03-05 14:47:18 volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 使用该关键字的例子如下: int volatile nVint; 当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 例如: volatile int i=10;int a = i;...//其他代码,并未明确告诉编译器,对i进行过操作int b = i; volatile指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b 中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。 关键字volatile有什么含意?并给出三个不同的例子。 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 1). 一个参数既可以是const还可以是volatile吗?解释为什么。 2). 一个指针可以是volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; } 下面是答案: 1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。(也就是说,const指定了我们的程序代码中是不可以改变这个变量的,但是volatile指出,可以是由于硬件的原因,在代码意外更改这个值,但是我们的代码同时会更新使用这个最新的数值) 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer 的指针时。(把指针声明为volatile的类型,可以保证指针所指向的地址随时发生变化) 3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

c语言经典笔试题(非常全)

1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 2. 写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。 #define MIN(A,B) ((A) <= (B) (A) : (B)) 4. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢? 这个问题用几个解决方案。我首选的方案是: while(1) { } 一些程序员更喜欢如下方案: for(;;) { } 第三个方案是用goto Loop: ... goto Loop; 5. 用变量a给出下面的定义 a) 一个整型数(An integer) b) 一个指向整型数的指针(A pointer to an integer) c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer) d) 一个有10个整型数的数组(An array of 10 integers) e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers) f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer) h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(An array of ten pointers to functions that take an integer argument and return an integer ) 答案是: a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 6. 关键字static的作用是什么?

C语言中volatile关键字的作用

C语言中volatile关键字的作用 一.前言 1.编译器优化介绍: 由于内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier),linux 提供了一个宏解决编译器的执行顺序问题。 void Barrier(void) 这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。 2.volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化。 二.volatile详解: 1.volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile 声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile 关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错) 2.看两个事例: 1>告诉compiler不能做任何优化

c语言中volatile的用法

c语言中volatile volatile:Tending to vary often or widely, as in price: 易波动的,不稳定的:易于经常或大幅度变化的,如价格: the ups and downs of volatile stocks. 易波动的股票沉浮 Inconstant; fickle: 易变的,多变的: a flirt's volatile affections. 浪荡子多变的爱情 Lighthearted; flighty: 活泼的,轻快的: in a volatile mood. 轻快的心情 Ephemeral; fleeting. 短暂的,易逝的 Tending to violence; explosive: 易爆发的;爆炸性的: a volatile situation with troops and rioters eager for a confrontation. 军队和暴民间爆炸性对立的局势 volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。 例如: volatile int i=10; int j = i; ... int k = i; volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。 而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile 可以保证对特殊地址的稳定访问,不会出错。 总结:如果一个变量可能会被除程序本身以外的其他因素改变,就必须声明为volatile

C中volatile关键字

详解C中volatile关键字 volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序: short flag; void test() { do1(); while(flag==0); do2(); } 这段程序等待内存变量flag的值变为1(怀疑此处是0,有点疑问,)之后才运行do2()。变量flag的值由别的程序更改,这个程序可能是某个硬件中断服务程序。例如:如果某个按钮按下的话,就会对DSP产生中断,在按键中断程序中修改flag为1,这样上面的程序就能够得以继续运行。但是,编译器并不知道flag的值会被别的程序修改,因此在它进行优化的时候,可能会把flag的值先读入某个寄存器,然后等待那个寄存器变为1。如果不幸进行了这样的优化,那么while循环就变成了死循环,因为寄存器的内容不可能被中断服务程序修改。为了让程序每次都读取真正flag变量的值,就需要定义为如下形式:volatile short flag; 需要注意的是,没有volatile也可能能正常运行,但是可能修改了编译器的优化级别之后就又不能正常运行了。因此经常会出现debug版本正常,但是release版本却不能正常的问题。所以为了安全起见,只要是等待别的程序修改某个变量的话,就加上volatile关键字。 volatile的本意是“易变的” 由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如: static int i=0; int main(void) { ... while (1) { if (i) do_something();

C语言关键字:auto、static、register、const、volatile 、extern 总结

auto 这个这个关键字用于声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。这个关键字不怎么多写,因为所有的变量默认就是auto的。 register 这个关键字命令编译器尽可能的将变量存在CPU内部寄存器中而不是通过内存寻址访问以提高效率。 static 常见的两种用途: 1>统计函数被调用的次数; 2>减少局部数组建立和赋值的开销.变量的建立和赋值是需要一定的处理器开销的,特别是数组等含有较多元素的存储类型。在一些含有较多的变量并且被经常调用的函数中,可以将一些数组声明为static类型,以减少建立或者初始化这些变量的开销. 详细说明: 1>、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。 2>、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。 3>当static用来修饰全局变量时,它就改变了全局变量的作用域,使其不能被别的程序extern,限制在了当前文件里,但是没有改变其存放位置,还是在全局静态储存区。 使用注意: 1>若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度; 2>若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度; 3>设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题(只要输入数据相同就应产生相同的输出)。 const 被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。它可以修饰函数的参数、返回值,甚至函数的定义体。

C语言几个重要的关键字之用法

Define 1.用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR(60*60*24*365)UL 我在这想看到几件事情: ?;#define语法的基本知识(例如:不能以分号结束,括号的使用,等等) ?;懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。 ?;意识到这个表达式将使一个16位机的整型数溢出-因此要用到 长整型符号L,告诉编译器这个常数是的长整型数。 ?;如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要 2.写一个"标准"宏MIN,这个宏输入两个参数并返回较小的一个。#define MIN(A,B)((A)<=(B)?(A):(B)) 这个测试是为下面的目的而设的: ?;标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方 法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是

必须的方法。 ?;三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。 ?;懂得在宏中小心地把参数用括号括起来 ?;我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事? least=MIN(*p++,b); Static 关键字static的作用是什么? 这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用: ?;在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 ?;在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变 量。 ?;在模块内,一个被声明为静态的函数只可被这一模块内的其它函

c语言中volatile关键字是什么含义

c语言中volatile关键字是什么含义 最佳答案volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。 例如: volatile int i=10; int j = i; ... int k = i; volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。 而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。 1.请问TCP/IP协议分为哪几层?FTP协议在哪一层? 答: TCP/IP整体构架概述 OSI的七层参考模型:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为: 应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。 传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。

C语言之volatile实例技巧讲解

volatile的本意是一般有两种说法--1.“暂态的”;2.“易变的”。 这两种说法都有可行。但是究竟volatile是什么意思,现举例说明(以Keil-c与a51为例例子来自Keil FQA),看完例子后你应该明白volatile的意思了,如果还不明白,那只好再看一遍了。 例1. void main(void) { volatile int i; int j; i=1;//1不被优化i=1 i=2;//2不被优化i=1 i=3;//3不被优化i=1 j=1;//4被优化 j=2;//5被优化 j=3;//6j=3 } ---------------------------------------------------------------------

例2. 函数: void func(void) { unsigned char xdata xdata_junk; unsigned char xdata*p=&xdata_junk; unsigned char t1,t2; t1=*p; t2=*p; } 编译的汇编为: 00007E00R MOV R6,#HIGH xdata_junk 00027F00R MOV R7,#LOW xdata_junk ;----Variable’p’assigned to Register’R6/R7’---- 00048F82MOV DPL,R7 00068E83MOV DPH,R6

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!注意 0008E0MOVX A,@DPTR 0009F500R MOV t1,A 000B F500R MOV t2,A ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 000D22RET 将函数变为: void func(void) { volatile unsigned char xdata xdata_junk; volatile unsigned char xdata*p=&xdata_junk; unsigned char t1,t2; t1=*p; t2=*p; } 编译的汇编为: 00007E00R MOV R6,#HIGH xdata_junk 00027F00R MOV R7,#LOW xdata_junk[Page] ;----Variable’p’assigned to Register’R6/R7’----

C语言中##的用法

C语言中##的用法 今天看linux操作系统源码是有这么一段: #define _syscall0(type,name) \ type name(void) \ { \ long __res; \ __asm__ volatile ( "int $0x80" \ // 调用系统中断0x80。 :"=a" (__res) \ // 返回 值??eax(__res)。 :"" (__NR_ ##name)); \ // 输入为系统中断调用号__NR_name。 if (__res >;= 0) \ // 如果返回值>;=0,则直接返

回该值。 return (type) __res; errno = -__res; \ // 否则置出错号,并返回-1。 return -1;} 其中有一个地方出现了两个‘#’号不明白什么意思,网上找到了一段论坛: 宏中"#"和"##"的用法 一、一般用法 我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. 用法: #include; #include; usingnamespacestd; #defineSTR(s) #s #defineCONS(a,b) int(a##e##b) intmain() {

printf(STR(vck)); //输出字符串"vck" printf("%d ",CONS(2,3)); //2e3输出:2000 return0; } 二、当宏参数是另一个宏的时候 需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开. 1,非'#'和'##'的情况 #defineTOW (2) #defineMUL(a,b)(a*b) printf("%d*%d=%d ",TOW,TOW,MUL(TOW,TOW)); 这行的宏会被展开为: printf("%d*%d=%d ",(2),(2),((2)*(2)));

相关主题
文本预览
相关文档 最新文档