做网站需要什么执照,软件公司网站,营销排名seo,国内简约网站设计static关键字1#xff0e;作用于变量#xff1a; 用static声明局部变量-------局部变量指在代码块{}内部定义的变量#xff0c;只在代码块内部有效#xff08;作用域#xff09;#xff0c;其缺省的存储方式是自动变量或说是动态存储的#xff0c;即指令执行到变量定义…
static关键字1作用于变量 用static声明局部变量-------局部变量指在代码块{}内部定义的变量只在代码块内部有效作用域其缺省的存储方式是自动变量或说是动态存储的即指令执行到变量定义处时才给变量分配存储单元跳出代码块时释放内存单元生命期。用static声明局部变量时则改变变量的存储方式生命期使变量成为静态的局部变量即编译时就为变量分配内存直到程序退出才释放存储单元。这样使得该局部变量有记忆功能可以记忆上次的数据不过由于仍是局部变量因而只能在代码块内部使用作用域不变。 用static声明外部变量-------外部变量指在所有代码块{}之外定义的变量它缺省为静态变量编译时分配内存程序结束时释放内存单元。同时其作用域很广整个文件都有效甚至别的文件也能引用它。为了限制某些外部变量的作用域使其只在本文件中有效而不能被其他文件引用可以用static关键字对其作出声明。总结用static声明局部变量使其变为静态存储方式作用域不变用static声明外部变量其本身就是静态变量这只会改变其连接方式使其只在本文件内部有效而其他文件不可连接或引用该变量。
2作用于函数使用static用于函数定义时对函数的连接方式产生影响使得函数只在本文件内部有效对其他文件是不可见的。这样的函数又叫作静态函数。使用静态函数的好处是不用担心与其他文件的同名函数产生干扰另外也是对函数本身的一种保护机制。
如果想要其他文件可以引用本地函数则要在函数定义时使用关键字extern表示该函数是外部函数可供其他文件调用。另外在要引用别的文件中定义的外部函数的文件中使用extern声明要用的外部函数即可。
参考资料
①《 C程序设计第二版 》谭浩强
②《 Pointers on C 》Kenneth A.Reek
void和void指针
void的含义 void即“无类型”void *则为“无类型指针”可以指向任何数据类型。void指针使用规范 ①void指针可以指向任意类型的数据亦即可用任意数据类型的指针对void指针赋值。例如 int *pint; void *pvoid; pvoid pint; /* 不过不能 pint pvoid; */ 如果要将pvoid赋给其他类型指针则需要强制类型转换如pint (int *)pvoid; ②在ANSI C标准中不允许对void指针进行算术运算如pvoid或pvoid1等而在GNU中则允许因为在缺省情况下GNU认为void *与char *一样。sizeof( *pvoid ) sizeof( char ). void的作用 ①对函数返回的限定。 ②对函数参数的限定。 当函数不需要返回值时必须使用void限定。例如 void func(int, int); 当函数不允许接受参数时必须使用void限定。例如 int func(void)。 由于void指针可以指向任意类型的数据亦即可用任意数据类型的指针对void指针赋值因此还可以用void指针来作为函数形参这样函数就可以接受任意数据类型的指针作为参数。例如 void * memcpy( void *dest, const void *src, size_t len ); void * memset( void * buffer, int c, size_t num ); 参考资料《 C/C语言void及void指针深层探索 》宋宝华函数指针
函数指针是什么 先来看函数调用是怎么回事。一个函数占用一段连续内存。当调用一个函数时实际上是跳转到函数入口地址执行函数体的代码完成后返回。如何找到对应的入口地址这是由函数名来标记的实际上函数名就是函数的入口地址。 函数指针是一种特殊类型的指针它指向一个函数的入口地址。 注意除了void类型指针是无类型的指针外其他所有指针都是有对应类型的例如int *pint、struct studentdata *psdata等只有指明了指针所指的数据类型编译器才能为指针分配或预计分配相应大小的存储空间指针的算术运算如pint等才是有意义的。因此定义了某种类型的指针之后除非使用强制类型转换那么它只能指向相应数据类型的变量或常量不同类型的指针或数据之间不可混用。所以指针的类型实际上是一种身份标志的作用。 函数指针如何表明自己的身份呢为了避免混乱必须也要作出相应规定不同函数的函数指针不能混用。例如int func1(int arg11, char arg12)与int func2(char arg)的函数指针就不能混用要定义可以指向func1的函数指针应该这样 int (*pfunc1)(int, char) func1定义可以指向func2的函数指针则该如下 int (*pfunc2)(char) func2; 从函数指针的定义可以看出函数指针的类型实际上是由函数签名决定的。函数签名就象是函数的身份证一个函数的函数签名是独一无二的具有相同函数签名的函数实际上就是同一函数。函数签名包括函数名、函数形参类型的有序列表和函数返回值类型。 一个函数指针的定义规定了它只能指向特定类型的函数。如果两个函数的形参列表和返回值类型相同只有函数名和函数体不同则可以使用相同类型的函数指针。例如如果还有一个函数int func3(char arg)则上面定义的可以指向函数func2的函数指针也可以用于指向func3即 pfunc2 func3; 再使用pfunc2(char ARG)就可以调用函数func3这时指令计数器PC指向函数入口从此开始执行函数体代码。 注意对函数指针进行算术运算也是没有意义的。如何使用函数指针 ①定义合适类型的函数指针变量 int (*pfunc)(int, int); ②给函数指针变量赋值使它指向某个函数入口 int example(int, int); pfunc example; /*将函数入口地址赋给函数指针变量*/ 或者pfunc example; /*函数名总是被编译器转换为函数指针入口地址来使用因此与上面一句等价 */ ③使用函数指针来调用相应的函数 retval pfunc(10, 16); 或者retval (*pfunc)(10, 16); 上面两句都与retval example(10, 16);等价。 理解一个指针变量p实际上也和普通的变量一样要占存储空间通常与平台的虚拟地址一样宽也有其自身的存储地址p不同的是在指针变量p的值有特殊的意义它是另外一个变量或常量的地址值也就是说在地址为p的存储单元上存放着另外一个数据的地址。因此*p实际上是将p看作它指向的数据的地址来使用*操作符是引用相应地址中的数据也就是对地址为p的存储单元中存放的数据进行操作。 一个函数指针变量则更为特殊。比如上面的例子pfunc变量本身的值是函数example()的入口地址。因此pfunc可以代替其所指函数的函数名来使用。至于*pfunc如果按照上面的理解它实际上是地址pfunc的内容也即函数example()的入口地址的内容就有点含糊了。不过从另一方面来理解如果使用pfunc example来初始化pfunc则*pfunc *(example) example又与pfunc等价。因此就有了两种使用函数指针来调用相应函数的形式。 值得注意的是不可用*pfunc来对pfunc的值初始化。即*pfunc example的写法是错误的。为什么要使用函数指针 前面介绍了函数指针的基本知识和使用规范。下面介绍函数指针的实际用途。不过首先要对前面的知识再做一个补充因为下面的应用很可能用到这一特性。前面指出除函数名之外的函数签名内容函数返回值类型和形参列表决定了函数指针的类型。实际上还有一种特殊的或说通用的函数指针在定义这类函数指针时只需要指定函数返回值类型而留空形参列表这样就可以指向返回值类型相同的所有函数。例如 int (*pfunc)(); 这样定义的pfunc就可以指向前面提到的func1和func2因为他们都返回整型值。 注意 int (*pfunc)()与int (*pfunc)(void)不是一回事后者不允许接受任何参数。 函数指针最常见的三个用途是 ①作为参数传递给其他函数。 这样可以把多个函数用一个函数体封装起来得到一个具有多个函数功能的新函数根据传递的函数指针变量值的不同执行不同的函数功能。这是函数嵌套调用难以实现的。参数的传递可以由程序员设定也可以由用户输入读取因此具有较大的灵活性和交互性。 另外还可以用于回调函数。使用void配合还可以将对不同数据类型的数据进行相同处理的多个函数封装为一个函数增强函数的生命力。 ②用于散转程序。 这种程序首先建立一个函数表实际上是一个函数指针数组表中存放了各个函数的入口地址或函数名根据条件的设定来查表选择执行相应的函数。这样也可以将多个函数封装为一个函数或者程序散转分支条件可以由程序员设定也可以由用户输入读取甚至是外设的某种特定状态这种状态可以是不受人为控制的。 ③实现C的面向对象的类的封装。 C语言中的struct与C中的class有很大不同除了缺省的成员属性外struct的成员缺省为public的可随意使用而class成员缺省为private的struct还很难实现类成员函数的封装。struct的成员一般都是数据成员而非函数成员。因此为了在C语言中为某个struct定义一套自己的函数对结构数据成员进行操作可以在struct结构体中增加函数指针变量成员在初始化时使它指向特定函数即可。 应用举例 ①假设定义了四个函数add(int, int)、sub(int, int)、mul(int, int)、div(int, int)可以将其封装为一个四则运算计算器函数: double calculator(int x, int y, int (*pfunc)(int, int)) { double result; result pfunc(x, y); return result; } 又例如在一个链表查询程序中要通过比较节点的特征值来查询节点不同类型的数据的比较方式不一样整型等可以直接比较字符串却要用专门的字符串操作函数为了使代码可重用性更高可以使用一个比较函数来代替各种不同数据类型的直接比较代码同时比较函数也必然是数据类型相关的因此要使用void指针和函数指针来转换为类型无关的比较函数根据相应的数据类型调用相应的函数传递相应的函数指针。一个实例是 int (*compare)(void const *, void const *); 这个函数指针可以接受任意类型的数据的指针参数同时返回int值作为比较结果标志。一个比较整型数据的比较函数是 int compare_ints(void const *a, void const *b) { if( *(int *)a *(int *)b ) return 0; else return 1; } ②散转程序。通过一个转移表函数指针数组来实现。还是上面定义的四个四则运算函数可以建立这样一个转移表注意初始化该转移表的语句前面应有add等相应函数原型声明或定义 double (*calculator[])(int, int) { add, sub, mul, div }; 这样calculator[0] add, calculator[1] sub, ... 使用result calculator[oper](x, y);就可以代替下面整个switch语句 switch( oper ) { case 0: result add(x, y); break; case 1: result sub(x, y); break; ... } ③C的面向对象化。一个对象包括数据和对数据的操作。C语言中的struct只有数据成员因此要增加一些“伪数据成员”即函数指针来实现对数据的操作。例如 #ifndef C_Class #define C_Class struct #endif C_Class student{ C_Class student *student_this char name; int height; int gender; int classnum; ... void (*Oper)( C_Class student *student_this ); ... } 参考资料①《 Pointers on C 》Kenneth A.Reek②《 C程序设计第二版》谭浩强③《 C语言嵌入式系统编程修炼之道 》
errno与错误处理errno是什么?在/usr/include/errno.h中,include了sys/errno.h,在该文件中定义了不同的errno的值(错误类型编号)所对应的宏以及错误类型.基本使用:#include errno.hextern int errno;1.使用perror( const char *msg )函数来将错误类型所对应的错误信息以字符串形式打印到终端.首先输出用户自定义的字符串msg(可以为空,即),然后打印错误信息.2.使用stderr( int errnum )将错误信息转换为字符串.3.注意,必须在函数表明操作失败后立刻对errno的值进行检查以找出对应错误.在使用它之前必须总是先将其值copy到另外一个变量保存起来,因为很多函数(象fprintf之类)自身就可能会改变errno的值.func( );errortype errno;printf( %d/n, errortype );或者if( errortype ... ) { do ...}else { do ....}
本文转载自http://hi.baidu.com/finalspeed/blog/item/d457747245dfe6178701b0b7.html