全局变量const怎么写c语言(嵌入式Linux开发C语言专题)
全局变量const怎么写c语言(嵌入式Linux开发C语言专题)int const *pconst int *p//const修饰数组const int a[4] = {1 2 3 4} int const a[4] = {1 2 3 4} //const修饰指针
C语言中的关键字总共有32个:auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while 但是,往往初学者很难会合理使用它们.这个小专题就主要讲解const static void volatile typedef sizeof register extern这些“特殊”关键字的使用方法,可以说能否很好的使用这些关键字可是展示一个C程序员的基本素养。学会了对这些关键字的使用,不仅仅对笔试、面试有帮助,更重要的是对自己以后做项目有很大帮助,别到时候项目主管看到你写的代码后对你失望吆。
这篇文章就先将const这个特殊的关键字。通过这篇文章,你将会搞懂以下代码:
//const修饰一般变量
const int i = 0; int const = 0;
//const修饰数组
const int a[4] = {1 2 3 4} int const a[4] = {1 2 3 4}
//const修饰指针
const int *p
int const *p
int * const p
const int * const p
//const修饰函数参数和返回值
char *strcpy(char *dest const char *src);
int strcmp(const char *s1 const char *s2);
(1)const全称:constant 也就是恒定不变的意思。如果说看到这个关键字只知道这个关键字是定义常量,那么请你好好看看这篇文章,因为你会有意想不到的收获。
(2)const不仅仅可以定义常量,被它所修饰的东西都受到某种强制保护,说白了就是加了const之后,可以访问但是不能再修改这个变量的值即这个变量是“只读的”。这样做可以提高程序的健壮性。还可以用const来修饰函数的参数、返回值。其中也涉及到const与指针的结合。
注意:在使用const修饰变量时,一定要给变量初始化,否则之后就不能赋值了!
(3)const修饰普通变量、数组和指针变量
在很多地方可能都见到const 类型名 变量名; const 类型名 *变量名;比如const int a; const int *a;const修饰的指针涉及到指针常量和常量指针。
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { const int i = 0; i = 1; return 0; }
运行结果:
分析结果:编译没有通过出错,编译器确实提醒我们变量i是只读变量,不能再进行复制操作。
1)const 类型名 变量名与 类型名 const 变量名 一样吗?
一样。将上面代码中const int i = 0;改为int const i = 0;结果一样。不过我们用的比较多和见得比较多的就是const int i = 0这种形式。
2)const 类型名 变量名[数组元素个数]与 类型名 const [数组元素个数] 一样吗?
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { //const int a[4] = {1 2 3 4}; //2种写法显示错误一样 int const a[4] = {1 2 3 4}; a[0] = 2;//想给数组中第一个元素重新赋值,但是失败,因为数组是只读的 return 0; }
运行结果:
分析结果:2种写法一样。但是编译没有通过,显示为read-only只读的。所以当我们要让数组中的不容不改变时可以用const关键字。
3)const 类型名 *变量名与 类型名 const *变量名 一样吗?
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { int a = 5; const int *i = &a; *i = 1; return 0; }
运行结果:
分析结果:编译没有通过,出错 因为const修饰的是*i
将上面代码中const int *i = 0;改为int const *i = 0;结果一样。 不过我们用的比较多和见得比较多的就是const int *i = 0这种形式。
将前面代码稍微改动一下,如下所示
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { int a = 5 b = 10; const int *i =&a; //*i = 1; //编译都没有通过,出错 i = &b; //编译通过,还可以间接访问操作*i printf("i = %d \n" *i); return 0; }
运行结果:
分析结果:不仅可以编译通过,也执行成功。原因是const int *i中的i是一个常量指针也即指针i是一个变量,它的值可以修改比如i=&a;但是*i的值不能变即指针所指向的地址中存储的内容不能变。
4)const 类型名 *变量名 与 类型名 * const 变量名 一样吗?
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { int a = 5 b=10; int * const i = &a; printf("修改之后 a = %d *i= %d\n" a *i); //i = &b; //编译都没有通过,出错 *i = 1; //编译通过,还可以间接访问操作修改变量a的值 printf("修改之后 a = %d *i= %d\n" a *i); return 0; }
运行结果:
分析结果:不一样 此处变量i是一个指针常量,也就是指针是恒定不变的,换句话说也是指针i所指向的这个地址值是固定的,在 int * const i = &a; 之后如果再i = &b; 就会出错。但是i这个地址中所存储的内容可以改变,比如原来*a=5后来*i = 1; 之后,a=1,因为*i将所执行的a的地址中存储的内容修改了。
5)const 类型名 * const 变量名?
可以拆分成2种:const 类型名 *变量名 和 类型名 * const 变量名 也就是前面所说的常量指针和指针常量。可以把const翻译为“常量”,*翻译为“指针”,按照他们出现的先后顺序来区分。const 类型名 *变量名中const在前 *在后,所以就是常量指针;同理 类型名 * const 变量名就是指针常量。指针指向的位置不能改变同时也不能通过这个指针改变变量的值。(不过仍然可以用其他的普通指针改变变量的值)。
#include <stdio.h> //演示const关键字用法 int main(int argc char** argv) { int a = 5 b = 10; const int * const i = &a; //i = &b; //修改变量i所执向的地址 出错 因为有int * const i //*i = 20; //修改变量i所执行向的地址存储的值 出错 因为有const int *i //直接通过间接访问操作符*访问变量i所执指向的 //变量a地址所存储的值是可以的 printf("a = %d *i= %d\n" a *i); return 0; }
(4)const修饰函数的参数和返回值
1)const修饰函数的参数
比如我们常用的字符串函数size_t strlen(const char *s);
char *strcpy(char *dest const char *src);
int strcmp(const char *s1 const char *s2);
如果参数是做输入使用,并且是按照“指针传递”,类似于size_t strlen(const char *s);这种形式,就可以加上const,可以确保在函数的函数体中意外修改指针指向地址所存储的内容。如果参数是做输入使用,但是按照“值传递”,因为函数将产生临时变量来复制该参数,因此不需要加上const,加上反而是多次一举,既不能提高效率也降低了函数的可理解性,更显示自己不会用const。
如果参数是做输出使用,不管是“值传递”还是“指针传递”方式,一定不要加const,否则该参数将失去输出功能。比如char *strcpy(char *dest const char *src);中的第一个参数dest就没有加const.
2)const修饰函数的返回值
这个有点不常用,但是确实也是一种情况。
如果以“指针传递”的方式来对函数的返回值加const,则表示此指针所指向地址的内容不能修改。返回值只能赋值给const修饰的同类型指针。比如const char* get_name(void);
使用时应该const char *name = get_name();而不是char *name = get_name();有些编译器可能会出错,有些可能不出错,为了保险期间,最好写成const char *name = get_name();
#include <stdio.h> const char *get_name(void); //演示const关键字用法 int main(int argc char** argv) { //const char *name = get_name();//没有编译警告 char *name = get_name();//会有编译警告 printf(" 函数返回之后地址 %p \n" name); //*name = "123"; //会出错,因为函数返回值类型是const char *不允许修改返回 的地址所存储的内容 printf(" name = %s \n" name); return 0; } const char *get_name(void) { char *str = "zhang san"; printf(" 函数返回之前地址 %p \n" str); return str; }
运行结果:
有编译警告
没有编译警告
分析结果:没有加const会有编译警告,加了就不会有编译警告,这是编译器帮我们做的。尽量加上const,在这个编译器中是警告,在别的编译器上可能就是错误了。函数返回之前和之后都是返回字符串str的地址,所以地址值相同。则输出zhang san 就理所当然了。
如果以“值传递”的方式来对函数的返回值加const,没有太大意义,与前面类似,因为函数会把返回值赋值给外部临时变量中。比如int get_name_id(void)写成const int get_name_id(void)。
这些结果都是经过笔者亲自测试的,希望大家在看后,一定要上机实战,可以加深理解。
后续继续更新...
更多精彩内容可以关注此头条号:嵌入式软硬件开发 喜欢的话大家可以“评论” “转发”、“点赞”或者“收藏”,感谢大家。相互交流,共同成长。