C语言深度解剖

合集下载

C语言中内存四区的详解

C语言中内存四区的详解

C语言中内存四区的详解C语言编程2022-05-10 14:00来自:今日头条,作者:抖点料er链接:https:///article/7046019680989037069/1、内存四区1.1数据类型本质分析1.1.1数据类型的概念•“类型”是对数据的抽象•类型相同的数据有相同的表示形式、存储格式以及相关的操作•程序中使用的所有数据都必定属于某一种数据类型1.1.2数据类型的本质•数据类型可理解为创建变量的模具:是固定内存大小的别名。

•数据类型的作用:编译器预算对象(变量)分配的内存空间大小。

•注意:数据类型只是模具,编译器并没有分酤空间,只有根据类型(模具)创建变量(实物),编译器才会分配空间。

1.2变量的本质分析1.2.1变量的概念概念:既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量。

变量定义形式:类型标识符,标识符,…,标识符;1.2.2变量的本质1、程序通过变量来申请和命名内存空间int a = 0。

2、通过变量名访问内存空间。

1.3程序的内存四区模型流程说明1、操作系统把物理硬盘代码load到内存2、操作系统把c代码分成四个区栈区( stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等堆区(heap):一般由程序员分配释放(动态内存申请与释放),若程序员不释放程序结束时可能由操作系统回收全局区(静态区)(statIc):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,该区域在程序结束后由操作系统释放常量区:字符串常量和其他常量的存储位置,程序结束后由操作系统释放。

程序代码区:存放函数体的二进制代码。

3、操作系统找到main函数入口执行1.4函数调用模型1.5函数调用变量传递分析(1)(2)(3)(4)(5)1.5栈的生长方向和内存存放方向相关代码:02_数据类型本质.c#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>int main(){int a;//告诉编译器,分配4个字节int b[10];//告诉编译器,分配4*10个字节/*类型本质:固定内存块大小别名可以通过sizeof()测试*/printf("sizeof(a)=%d,sizeof(b)=%d\n", sizeof(a), sizeof(b));//打印地址//数组名称,数组首元素地址,数组首地址printf("b:%d,&b:%d\n",b,&b);//地址相同//b,&b数组类型不同//b,数组首地址元素一个元素4字节,+1 地址+4//&b,整个数组首地址一个数组4*10=40字节, +1 地址+40 printf("b+1:%d,&b+1:%d\n", b + 1, &b + 1);//不同//指针类型长度,32位机器32位系统下长度是 4字节// 64 64 8char********* p = NULL;int* q = NULL;printf("%d,%d\n", sizeof(p), sizeof(q));//4 , 4return0;}03_给类型起别名.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>typedef unsigned int u32;//typedef 和结构体结合使用struct Mystruct{int a;int b;};typedef struct Mystruct2{int a;int b;}TMP;/*void 无类型1.函数参数为空,定义函数时用void修饰 int fun(void)2.函数没有返回值:使用void void fun (void)3.不能定义void类型的普通变量:void a;//err 无法确定是什么类型4.可以定义 void* 变量 void* p;//ok 32位系统下永远是4字节5.数据类型本质:固定内存块大小别名6.void *p万能指针,函数返回值,函数参数*/int main(){u32 t;//unsigned int//定义结构体变量,一定要加上struct 关键字struct Mystruct m1;//Mystruct m2;//errTMP m3;//typedef配合结构体使用struct Mystruct2m4;printf("\n");return0;}04_变量的赋值.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>int main(){//变量本质:一段连续内存空间别名int a;int* p;//直接赋值a = 10;printf("a=%d\n", a);//间接赋值printf("&a:%d\n", &a);p = &a;printf("p=%d\n", p);*p = 22;printf("*p=%d,a=%d\n", *p, a);return0;}05_全局区分析.c#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>int main(){//变量本质:一段连续内存空间别名int a;int* p;//直接赋值a = 10;printf("a=%d\n", a);//间接赋值printf("&a:%d\n", &a);p = &a;printf("p=%d\n", p);*p = 22;printf("*p=%d,a=%d\n", *p, a);return0;}06_堆栈区分析.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>char* get_str(){char str[] = "abcdef";//内容分配在栈区,函数运行完毕后内存释放printf("%s\n", str);return str;}char* get_str2(){char* temp = (char*)malloc(100);if (temp == NULL){return NULL;}strcpy(temp, "abcdefg");return temp;}int main(){char buf[128] = { 0 };//strcpy(buf,get_str());//printf("buf = %s\n", buf);//乱码,不确定内容char* p = NULL;p = get_str2();if (p != NULL){printf("p=%s\n", p);free(p);p = NULL;}return0;}07_静态局部变量.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>int* getA(){static int a = 10;//在静态区,静态区在全局区return &a;}int main(){int* p = getA();*p = 5;printf("%d\n",);return0;}08_栈的生长方向.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#include<string.h>#include<time.h>int* getA(){static int a = 10;//在静态区,静态区在全局区return &a;}int main(){int* p = getA();*p = 5;printf("%d\n",);return0;}版权申明:内容来源网络,版权归原创者所有。

对c语言的认识和理解

对c语言的认识和理解

对c语言的认识和理解对C语言的认识和理解一、C语言的背景和特点C语言是一种通用的高级编程语言,由美国贝尔实验室的Dennis Ritchie在20世纪70年代初开发。

C语言是一种静态类型、过程化、结构化的编程语言,具有高效性、可移植性和灵活性等特点。

1. 高效性:C语言以底层为基础,直接操作内存和硬件资源,因此执行效率高。

它提供了丰富的数据类型和运算符,可以进行精确控制和优化。

2. 可移植性:C语言编写的程序可以在不同平台上进行编译和运行。

这是因为C语言定义了基本数据类型和函数库,并使用标准化的编译器来保证代码在不同系统上的兼容性。

3. 灵活性:C语言提供了丰富而灵活的控制结构,如条件判断、循环等,使程序员可以自由地控制程序流程。

同时,C语言还支持指针操作,使得程序能够直接访问内存地址。

二、C语言的应用领域1. 操作系统开发:由于C语言具有高效性和可移植性,在操作系统开发中得到广泛应用。

Unix、Linux和Windows等操作系统的核心部分都是用C语言编写的。

2. 嵌入式系统开发:C语言可以直接访问硬件资源,因此在嵌入式系统开发中也得到了广泛应用。

嵌入式系统包括智能手机、汽车电子、家电等领域。

3. 游戏开发:C语言提供了丰富的数据类型和运算符,并支持底层操作,使其成为游戏开发的首选语言。

许多经典游戏如《魂斗罗》和《马里奥》都是用C语言编写的。

4. 数据库管理系统:C语言可以与数据库进行交互,实现数据的存储和检索。

常见的数据库管理系统如MySQL和Oracle等都使用了C语言进行开发。

三、C语言基本概念1. 变量和数据类型:在C语言中,变量是用来存储数据的容器,必须先声明后使用。

常见的数据类型包括整型、浮点型、字符型等,可以根据需要选择合适的数据类型。

2. 运算符:C语言提供了丰富的运算符,包括算术运算符、关系运算符、逻辑运算符等。

这些运算符可用于对变量进行计算和比较。

3. 控制结构:C语言提供了多种控制结构,包括条件判断、循环和跳转等。

c语言基本结构

c语言基本结构

c语言基本结构C语言是一种通用的编程语言,它具有高效、简洁、可移植等特点。

在学习C语言时,了解其基本结构是非常重要的。

本文将详细介绍C语言的基本结构。

一、程序的基本组成部分1.1. 注释注释是程序中用来解释代码含义的部分,它不会被编译器识别和执行。

在C语言中,注释可以使用两种方式:单行注释和多行注释。

1.2. 预处理器指令预处理器指令是在编译之前对源代码进行处理的指令。

它们以“#”开头,并且不以分号结尾。

预处理器指令可以用来定义常量、包含头文件等操作。

1.3. 函数函数是程序中完成特定任务的独立模块。

每个函数都有一个唯一的名称,并且可以接受参数和返回值。

1.4. 变量变量是程序中存储数据的容器。

在C语言中,变量必须先声明后使用,并且需要指定其类型和名称。

1.5. 语句语句是程序中最小的可执行单元。

每个语句必须以分号结尾。

二、C程序的执行过程2.1. 编译阶段在编译阶段,编译器将源代码转换为目标代码。

这个过程包括词法分析、语法分析、语义分析等步骤。

2.2. 链接阶段在链接阶段,将目标代码和库文件链接在一起,生成可执行文件。

2.3. 运行阶段在运行阶段,操作系统加载可执行文件到内存中,并执行程序。

三、C程序的基本语法3.1. 标识符标识符是指变量、函数等的名称。

在C语言中,标识符必须以字母或下划线开头,并且不能是关键字。

3.2. 数据类型数据类型是指变量可以存储的数据类型。

C语言中有基本数据类型和派生数据类型。

基本数据类型包括整型、浮点型、字符型等。

派生数据类型包括数组、结构体、共用体等。

3.3. 运算符运算符是用来对变量进行操作的符号。

C语言中有算术运算符、关系运算符、逻辑运算符等。

3.4. 控制语句控制语句是用来控制程序流程的语句。

C语言中有条件语句(if-else)、循环语句(for、while)、跳转语句(break、continue)等。

四、示例程序下面是一个简单的C语言程序,用来计算两个数的和:#include <stdio.h>int main(){int a, b, sum;printf("请输入两个整数:\n");scanf("%d%d", &a, &b);sum = a + b;printf("它们的和是:%d\n", sum);return 0;}以上程序中,第一行包含了头文件<stdio.h>,用来引入标准输入输出函数。

C语言深度解剖_121113

C语言深度解剖_121113

关键字Auto:声明自动变量。

在缺省情况下,编译器默认所有变量都是auto的定义和声明:int I;定义就是创建一个对象,为这个对象分配一块内存并给他取一个名字。

一个变量或对象只能定义一次Extern int i声明:告诉编译器,这个名字已经匹配到一块内存上,这个名字已经被预定,别的地方不能再用他当变量名或对象名。

声明可以出现多次Extern可以置于变量或函数前,以表明变量或函数的定义在别的文件中Register:请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问注意点,register变量必须是能被CPU寄存器所接受的类型,这就是说register变量必须是单值,并且其长度小于或等于整型的长度。

而且变量不能用取地址符&Static作用:1修饰退出一个块后仍然存在的局部变量2表示不能被其他文件访问的全局变量和函数静态全局变量,作用域仅限于变量被定义的文件中,其他文件及时使用extern声明也没法使用它。

静态局部变量,在函数体里面定义的,就只能在这个函数里使用,同一个文档中的其他函数也用不了。

由于被static修饰的变量总是存在内存的静态区。

当这个函数运行结束,静态变量也不会销毁修饰函数:指对函数的作用域限于本文件,使用静态函数的好处是,不同的人编写不同的函数时,不用担心自己定义的函数是否会有其他文件中的函数同名Bool变量的初始化和if条件句的规范Bool bTestFlag=FALSE;If(bTestFlag); if(!bTestFlag);float变量的初始化和if条件句的规范float fTestVal=0.0;if((fTestVal>=-EPSINON)&&(fTestVal<=EPSINON));指针变量Int *p=NULL;If(NULL==p); if(NULL!=p);Case后面只能是整型或字符型的常量或常量表达式按字母顺序排列各条case语句按执行频率排列case语句Break表示终止本层循环在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的放在最外层,以减少CPU跨切循环层的次数如果函数的参数可以是任意类型指针,那么应声明其参数为void*如内存操作函数void* memcpy(void* dest,const void* src,size_t len)Return语句不能反悔指向栈内存的指针,因为该内存在函数体结束时被自动销毁如char *Func(void){Char str[30];…..Return str;}Const修饰的只读变量先忽略类型名,看const离哪个近就修饰谁Const int *p 修饰*p,*p是指针指向的对象,不可变int * const p 修饰p,p不可变const修饰函数的返回值,返回值不可被改变const int Fun (void)volatile关键字修饰的变量,提醒编译器对访问该变量的代码不再进行优化int i=10;in j=I; //1语句int k=I; //2语句执行上面代码时编译器对代码优化,在1语句时从内存中取出i的值赋给j之后,这个值并没有丢掉,而是在2语句时继续用这个值给k赋值Volatile int i=10;Int j=I;Int k=I;执行上面代码,volatile关键字告诉编译器,i是随时可能发生变化的,每次使用他的时候必须从内存中取出i的值Union中所有的数据成员公用一个空间,所有的数据成员具有相同的起始地址大端模式:字数据的高字节存储在低地址中,低字节存放在高地址中小端模式:字数据的高字节存储在高地址中,低字节存放在低地址中Typedef:给一个已经存在的数据类型(注意:是类型,不是变量)其一个别名Typedef struct student{//code}Stu_st,*Stu_pststruct student *stu1、Stu_pst stu、Stu_st *stu——没有区别表示给struct student{//code}取了个别名叫Stu_st,同时给struct student{//code}*取了个别名叫Stu_pstConst Stu_pst stu2这里Stu_pst是struct student{//code}*的别名。

C语言编译过程总结详解

C语言编译过程总结详解

C语言编译过程总结详解C语言的编译过程可以分为四个主要阶段:预处理、编译、汇编和链接。

下面会详细解释每个阶段的工作原理。

1.预处理阶段:预处理器的主要作用是根据源文件中的预处理指令对源代码进行一系列的文本替换和宏展开,生成经过预处理的源代码文件。

预处理指令以"#"开头,主要包括#include、#define、#ifdef等。

预处理器的工作原理如下:- 处理#include指令:将包含的头文件内容插入到当前位置,形成一个单独的源代码文件。

- 处理#define指令:将宏定义替换为对应的内容。

- 处理#ifdef指令:根据条件判断指令是否执行。

预处理阶段生成的文件以".i"为后缀,可以用编译器提供的预处理器命令进行预处理,如gcc -E source.c -o source.i。

2.编译阶段:编译器将预处理阶段生成的经过预处理的源文件进行词法分析、语法分析、语义分析和优化,生成汇编代码。

编译阶段包括以下几个步骤:-词法分析:将源代码分解成一个个的词法单元,如标识符、关键字、常量等。

-语法分析:分析和验证词法单元之间的语法关系,生成语法树。

-语义分析:对语法树进行语义检查,如类型检查、变量声明检查等。

-优化:进行编译优化,如常量折叠、无用代码删除等。

编译阶段生成的文件以".s"为后缀,可以用编译器提供的编译器命令将汇编代码转化为可执行文件,如gcc -S source.i -o source.s。

3.汇编阶段:汇编器将编译阶段生成的汇编代码转化为机器码。

汇编阶段包括以下几个步骤:-符号解析:将符号(如函数名、变量名)与其对应的地址进行关联。

-指令生成:将汇编代码转化为机器码。

汇编阶段生成的文件以".o"为后缀,可以用编译器提供的汇编器命令将目标文件转化为可执行文件,如gcc -c source.s -o source.o。

C 语言深度解剖重点总结(经典)

C 语言深度解剖重点总结(经典)

《C 语言深度解剖》总结(陈正冲编著)1.register关键字请求编译器尽可能的将变量存储在CPU内部寄存器中而不是内存中以提高访问效率。

数据从内存中取出来首先放到寄存器中,然后CPU再从寄存器中读取数据来进行处理,处理完后同样通过寄存器放到内存中,CPU不直接和内存打交道。

Register的值必须是一个单个的值,并且其长度应小于或等于int的长度,而且register 变量可能不放在内存中,所以不能用取地址符(&)来获取register变量的地址。

2. #include <cstdlib>#include <iostream>using namespace std;int main(int argc, char *argv[]){char a[1000];for(int i=0; i<1000; i++)a[i] = -1 - i;cout << strlen(a) << endl;system("PAUSE");return EXIT_SUCCESS;}输出结果为:255先来了解下补码的知识:在计算机中,数值一律用补码来表示(存储),主要原因是使用补码,可以将符号位和其它位统一处理,同时,减法也可以按加法来处理,两外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍去。

整数的补码和其原码一致,负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1.于是,for()循环中,当i = 255时,a[255] = -256, 由于char类型的只能表示-128~127之间的数,所以-256已经发生了溢出,只将最低8位赋给a[255], -256的补码的低8位为0,所以a[255] = 0, 也就是字符串的结尾符’\0’的ascii值,当用strlen()计算a的长度时,遇到a[255]时停止,于是strlen(a) = 255; (a[0]~a[254])3. 下面输出:#include <iostream>#include <string>#include <bitset>using namespace std;int main(){//freopen("output.txt", "wt", stdout);int i = -20;unsigned j = 10;bitset<32> b(i + j);int res = i + j;cout << b << endl;cout << hex << i + j << endl;cout << dec << res << endl;system("PAUSE");return 0;}输出结果:11111111111111111111111111110110fffffff6-10分析:当表达式中既有signed和unsigned时,计算结果为unsigned类型的,所以i + j的结果也是unsigned类型的,i + j = -10, -10的补码可以按照上面说的计算补码的介绍得出…如果把i + j的结果复制给int类型的,则-10的补码会被解析成有符号类型的,故res 的输出为-10;4.#include <iostream>#include <string>using namespace std;int main(){unsigned i;for(i=9; i>=0; i--)cout << "#####" << endl;system("PAUSE");return 0;}程序将无限的输出####, 因为i为unsigned类型的,永远>=0, 所以上面的for()是个死循环…5.如果函数没有返回值,那么声明为void 类型。

深入了解C语言

深入了解C语言
我们主要目标是研究蓝色的C语言的代码,第一句start.asm所生成的代码太简单,就是调用e_main函数.而我们的e_main函数就是蓝色代码部分.
从C源程序中我们看到,我们在e_main做的就是一件事情:调用e_putchar(ch);其中ch是传给出e_putchar的参数.
MOV AX,000B
这段代码我将用nasm来进行编译.生成start.obj
nasmw -f obj -o start.obj start.asm
下面我们用Turboc C来编译这段C代码:
TCC -mt -oexample1.obj -c example1.c
link start.obj example1.obj,example1.exe,,,
DGROUP group _TEXT
assume cs:_TEXT,ds:DGROUP,ss:DGROUP
public _k_putchar
_k_putchar proc near
push bp
mov bp,sp
mov ah,0eh
mov bx,7h
mov al,byte ptr [bp+4]
深入了解C语言
这一节我们主要来研究一下C语言如何使用函数中的局部变量的.C语言中对于全局变量和局部变量所分配的空间地址是不一样的.全局变量是放在_DATA段,也就是除开_TEXT代码段的另一块集中的内存空间.而局部变量主要是使用堆栈的内存空间.好了,让我们直接看看下面这个案例研究.
研究案例三
; C程序的入口 start.asm
[BITS 16]
[global start]
[extern _e_main]

C 语言深度解剖学习笔记

C 语言深度解剖学习笔记

C语言深度解剖学习笔记《C语言深度解剖》前言:如果本书上面的问题能真正明白80%,作为一个应届毕业生,肯怕没有一家大公司会拒绝你。

第一章关键字什么是定义?什么是声明?什么是定义:所谓的定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。

但注意,这个名字一旦和这块内存匹配起来,它们就同生共死,终生不离不弃。

并且这块内存的位置也不能被改变。

一个变量或对象在一定的区域内(比如函数内,全局等)只能被定义一次,如果定义多次,编译器会提示你重复定义同一个变量或对象。

什么是声明:有两重含义,如下:第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,下面的代码用到变量或对象是在别的地方定义的。

声明可以出现多次。

第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。

定义声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存C语言标准定义的32个关键字关键字意义auto声明自动变量,缺省时编译器一般默认为autoint声明整型变量double声明双精度变量long声明长整型变量char声明字符型变量float声明浮点型变量short声明短整型变量这六个关键字代表C语言里的六种基本数据类型在32位的系统上short内存大小是2个byte;int内存大小是4个byte;long内存大小是4个byte;float内存大小是4个byte;double内存大小是8个byte;char内存大小是1个byte。

(注意这里指一般情况,可能不同的平台还会有所不同,具体平台可以用sizeof关键字测试一下)signed声明有符号类型变量unsigned声明无符号类型变量正负数:最高位如果是1,表明这个数是负数。

如果最高位是0,表明这个数是正数struct声明结构体变量不要认为结构体内不能放函数\union声明联合数据类型union只配置一个足够大的空间以来容纳最大长度的数据成员enum声明枚举类型成员都是常量,也就是我们平时所说的枚举常量(常量一般用大写)。

C语言包括哪些东西-哪些部分重要,哪些部分需要着重理解-_0

C语言包括哪些东西-哪些部分重要,哪些部分需要着重理解-_0

C语言包括哪些东西?哪些部分重要,哪些部分需要着重理解?最近做完了聊天室的项目,C语言基础的学习阶段也算是告一段落了,但我对C语言还是只是一个入门,就像一个工具,我现在只是了解、会初步使用它了,但并没有达到如臂挥使的地步,今后还需要对C语言进行更深入的学习,今天我就讲一下我个人学到现在对C语言的认识,自己的理解,若有错误,还望指出,不甚感激。

首先是C语言整体的脉络,C语言包括哪些东西?哪些部分重要,哪些部分需要着重理解?这是我经常问自己的两个问题。

首先,C语言有哪些东西?C语言的东西其实并不是太多:1、最基本的一些数据类型及其所占的内存大小、还有一些基础的计算机常识(进制转换等)。

这些东西在对C语言有了一定的了解后都是比较容易的。

2、三种逻辑(顺序、选择和循环)顺序语句就是从上到下没有判断,一步到底的语句。

选择语句就是if和switch语句,在特定的场合,switch语句使用会使程序看的简单明了,尤其是选择情况较多的时候。

大多数时候if语句用的多一点。

循环语句就是while、do...while、和for语句,这三个do...while我用的不是太多,就不做评价了。

while语句和for语句用的场合非常多,我说一下几个注意点:a、在多层循环中,尽可能把最长的循环放在最外围,节省cpu的资源。

b、不能在循环体内修改循环变量,防止循环失控。

c、循环尽可能的短,太多行的循环代码会大大的影响阅读。

解决方法:使用子函数处理d、把循环嵌套控制在3层以内,超过三层,对代码的理解难度大大增加了。

e、for语句的控制表达式不能包含任何浮点类型的对象还有就是break和continue语句,经常会有人问我,这两个关键字跳出的是什么,break是跳出离它最近的一个循环(switch中的是跳出switch,不是跳出循环),continue也是一样。

3、数组和指针数组我把它分为两个:普通数组和字符串,其中对字符串的操作就是C语。

C语言深度解剖

C语言深度解剖

目录目录 (1)第一章关键字 (2)do 循环语句的循环体 (2)1.1,最宽恒大量的关键字----auto (2)1.2,最快的关键字---- register (2)1.2.1,皇帝身边的小太监----寄存器 (2)1.2.2,使用register 修饰符的注意点 (3)1.3,最名不符实的关键字----static (3)1.3.1,修饰变量 (3)1.3.2,修饰函数 (3)1.4,基本数据类型----short、int、long、char、float、double (3)1.4.1,数据类型与“模子” (3)1.4.2,变量的命名规则 (3)1.5,最冤枉的关键字----sizeof (4)1.5.1,常年被人误认为函数 (4)1.5.2,sizeof(int)*p 表示什么意思? (5)1.6,if、else 组合 (5)1.7,switch、case 组合 (6)1.8,do、while、for 关键字 (7)1.9,goto 关键字 (8)1.10,void 关键字 (8)1.11,return 关键字 (9)1.12,最易变的关键字----volatile (10)1.13,最会带帽子的关键字----extern (10)1.14,struct 关键字 (11)1.16,enum 关键字 (12)1.17,伟大的缝纫师----typedef 关键字........................12 第二章符号 (13)2.2,接续符和转义符 (15)2.3,单引号、双引号 (15)2.4,逻辑运算符 (15)2.5,位运算符 (15)2.6,花括号 (15)2.7,++、--操作符 (15)2.8,2/(-2)的值是多少? (16)2.9,运算符的优先级 (16)3.8,##预算符 (21)4.1,指针 (21)4.2,数组 (23)4.2.2,省政府和市政的区别----&a[0]和&a 的区别 (23)4.3,指针与数组之间的恩恩怨怨 (23)4.4,指针数组和数组指针 (25)4.4.4,地址的强制转换 (26)4.5,多维数组与多级指针 (26)4.5.2,二级指针 (27)4.6,数组参数与指针参数 (27)4.6.2,一级指针参数 (28)4.7,函数指针 (29)4.7.5,函数指针数组的指针 (30)第五章内存管理 (30)5.1,什么是野指针 (30)5.2,栈、堆和静态区 (30)5.3,常见的内存错误及对策 (31)第六章函数 (33)6.1,函数的由来与好处 (33)6.2,编码风格 (33)第七章文件结构 (36)7.1,文件内容的一般规则 (36)7.2,文件名命名的规则 (37)第一章关键字每次讲关键字之前,我总是问学生:C 语言有多少个关键字?sizeof 怎么用?它是函数吗?有些学生不知道C 语言有多少个关键字,大多数学生往往告诉我sizeof 是函数,因为它后面跟着一对括号。

简述c语言程序的结构

简述c语言程序的结构

C语言程序的结构引言C语言是一种高级程序设计语言,它以其简洁、高效和可移植性而闻名。

在编写C语言程序时,了解C语言程序的结构是非常重要的。

本文将介绍C语言程序的结构,深入探讨每个部分的功能和作用。

C语言程序的结构概览一个典型的C语言程序通常包含以下几个部分: 1. 头文件 2. 定义常量和宏 3. 全局变量声明 4. 函数声明 5. 主函数 6. 定义其他函数下面将逐个部分详细介绍。

头文件头文件是C语言程序的第一个部分,它用于引入需要使用的库文件和声明全局变量等。

头文件以.h为后缀,通常通过使用#include指令来包含。

常见的头文件有stdio.h、stdlib.h等,它们包含了C语言中常用的函数和常量的声明。

定义常量和宏在C语言程序中,常常需要使用一些固定不变的值,这些值可以通过定义常量和宏来表示。

常量一般使用const关键字进行定义,而宏则使用#define指令进行定义。

在定义常量和宏时,通常使用大写字母命名,以便和变量进行区分。

常量和宏的定义可以提高程序的可读性和维护性。

全局变量声明全局变量是在函数外部定义的变量,它的作用范围为整个程序。

在C语言中,全局变量的声明通常放在函数之外,在使用前进行声明。

全局变量可以在不同的函数中共享和访问,但也容易造成变量命名冲突和代码可读性降低,因此在使用全局变量时需要谨慎。

函数声明函数是C语言程序的重要组成部分,它用于封装一系列的操作,可以重复利用。

函数在C语言中以函数原型的形式进行声明。

函数声明包括函数返回类型、函数名和参数列表等信息。

在函数声明中,可以使用extern关键字来声明在其他文件中定义的函数。

主函数C语言程序中的主函数是程序的入口,它是程序执行的起点。

主函数的形式如下:int main(){// 主函数的代码return 0;}主函数中的代码完成程序的初始化、输入输出等操作,在主函数的最后使用return 语句返回一个整数值,通常是0,表示程序正常运行结束。

深入理解C语言的内存管理

深入理解C语言的内存管理

深入理解C语言的内存管理之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少。

问题不能拖,我这就来学习一下吧,争取一次搞定。

在任何程序设计环境及语言中,内存管理都十分重要。

内存管理的基本概念分析C语言内存的分布先从Linux下可执行的C程序入手。

现在有一个简单的C源程序hello.c1 #include <stdio.h>2 #include <stdlib.h>3 int var1 = 1;45 int main(void) {6 int var2 = 2;7 printf("hello, world!\n");8 exit(0);9 }经过gcc hello.c进行编译之后得到了名为a.out的可执行文件[tuhooo@localhost leet_code]$ ls -al a.out-rwxrwxr-x. 1 tuhooo tuhooo 8592 Jul 22 20:40 a.outls命令是查看文件的元数据信息[tuhooo@localhost leet_code]$ file a.outa.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=23c58f2cad39d8b15b91f0cc8129055833372afe, not strippedfile命令用来识别文件类型,也可用来辨别一些文件的编码格式。

它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的。

[tuhooo@localhost leet_code]$ size a.outtext data bss dec hex filename(代码区静态数据)(全局初始化静态数据)(未初始化数据区)(十进制总和)(十六制总和)(文件名)1301 560 8 1869 74d a.out显示一个目标文件或者链接库文件中的目标文件的各个段的大小,当没有输入文件名时,默认为a.out。

C语言深度解剖读书笔记

C语言深度解剖读书笔记

C语言深度解剖读书笔记之——C语言基础测试题前几天天看到这本书,感觉不错,在看之前,先做了后面的习题,结果只得了60多分,一直以为自己的基础还是不错的,做完后对了答案后,感觉自己的自信心一下全没有了,不过遇到问题解决问题,我用了2天时间好好研读了这本书,感觉真不错。

虽然感觉都是一些基础的知识,但是我读的还是津津有味,感觉收获蛮多的,感谢这本书的作者陈正冲。

呵呵,说来我本科专业和这位大牛还是同一个专业呢,呵呵。

不是只有计算机科班出身的才能学好编程,知真正的高手都是自学的。

今天就把我当时做错的题目和认为比较好的题目一个个写出来。

再次分析下如果我在哪家公司遇到类似这种题目我会感觉这家公司出题很有水平,重基础,真正理解C 语言的人才能得高分。

注重细节,知其然知其所以然。

题目1.下面代码有什么问题,为什么?[cpp]view plaincopyprint?1.#include <iostream>ing namespace std;3.4.int _tmain(int argc, _TCHAR* argv[])5.{6.char string[10],str1[10];7.int i;8.for (i=0;i<10;i++)9.{10.str1[i] = 'a';11.}12.strcpy(string,str1);13.cout<<string<<endl;14.system("pause");15.return 0;16.}运行的时候回出现下面情况:error1.exe 中的0xcccc6161 处未处理的异常: 0xC0000005: Access violation做这个题目的时候,我也知道字符串strcpy是以'\0'为结束标识的。

会产生数组越界,但是表达不清楚。

答案:运行到strcpy的时候可能会产生内存异常。

C语言深度解剖读书笔记

C语言深度解剖读书笔记

C语⾔深度解剖读书笔记开始本节学习笔记之前,先说⼏句题外话。

其实对于C语⾔深度解剖这本书来说,看完了有⼀段时间了,⼀直没有时间来写这篇博客。

正巧还刚刚看完了国嵌唐⽼师的C语⾔视频,觉得两者是异曲同⼯,所以就把两者⼀起记录下来。

等更新完这七章的学习笔记,再打算粗略的看看剩下的⼀些C语⾔的书籍。

本节知识:1.c语⾔中⼀共有32个关键字,分别是:auto、int、double、long、char、short、float、unsigned、signed、sizeof、extern、static、goto、if、else、struct、typedef、union、enum、switch、case、break、default、do、while、const、register、volatile、return、void、for、continue。

注意:define、include这些带#号的都不是关键字,是预处理指令。

2.定义与声明:定义是创建⼀个对象并为⽌分配内存。

如:int a;声明是告诉编译器在程序中有这么⼀个对象,并没有分配内存。

如: extern int a;3.对于register这个关键字定义的变量,不能进⾏取地址运算(&),因为对于x86架构来说,地址都是在内存中的,不是在寄存器中的,所以对寄存器进⾏取地址是没有意义的。

并且应该注意的是给register定义的变量,应该赋⼀个⽐寄存器⼤⼩要⼩的值。

注意:register只是请求寄存器变量,但是不⼀定申请成功。

4.关键字static:=对于static有两种⽤法:a.修饰变量:对于静态全局变量和静态局部变量,都有⼀个特点就是不能被作⽤域外⾯,或外⽂件调⽤(即使是使⽤了extern也没⽤)。

原因就是它是存储在静态存储区中的。

对于函数中的静态局部变量还有⼀个问题,就是它是存在静态存储区的,即使函数结束栈区收回,这个变量的值也不改变。

static int i=0; 这是⼀条初始化语句⽽不是⼀条赋值语句所以跟i=0不⼀样的。

C语言基础详解

C语言基础详解

C语言基础详解我们来简单复习一下,我们之前所讲的内容,一起来回顾回顾。

我们之前呢从刚开始的时候,讲的c语言。

其实c语言是一个非常古老的语言了,1941年,为什么会出c语言呢?因为当时没有好语言,最先进的语言是b语言。

入门的时候学这个比较好,计算机程序啊,一般语言的话,第一个是变量和数据类型对不对?第一个就是变量和数据类型,第二个呢?就是分支结构和循环结构。

第三点呢就是这个数组,第四个就是常用的算法,所以呢这里就是,在学c语言的时候,其实我们一定要抛开这个语言的芥蒂,其实我们不只是学c语言这一个语言。

实际上我们学的是整个计算机编程的这样的一件事。

你c语言学习完了之后的话,我们再遇到java啊遇到c#啊,甚至步入到其他的一些语言的时候,是非常快的。

因为很多语言的话他基本上都有这些要素。

我们回顾一下变量和数据类型,对吧,我们以前讲的,那变量呢,什么叫变量啊?变量就是一块内存空间,对不对?那有了变量以后的话,为什么还需要数据类型呢?对不对?因为数据类型这个东西的话呢,他是用来规定变量你到底有多大的。

就像我们之前讲的规则,中国有这么多的官儿,这么多的族长,分多大的房子。

一个乡长分多大的房子。

程序里的数据类型呢,实际上也决定了我们的一个变量占多大的内存空间,我们所学的变量数据类型就这么几个。

有整型有长整型,有短整型。

整型完了之后我们还有浮点型float类型和double类型。

单精度浮点型和双精度浮点型。

Double是双精度浮点型。

一般我们常用的就是double类型的,对不对,除此之外我们还有c语言里面常用的类型。

实际上这几个类型的话呢,日后我们学的复杂了之后呢,我们会发现,他甚至可以组成一些复杂的类型,对不对,比如以前我们用的那个背包,你想,游戏里的背包,那游戏里的背包的话呢。

他又是通过什么组成的,背包的话,也可以把他理解成一个数据类型,只是背包的话他有很多很多的小东西组成的,对不对,背包里面的话有元素、对不对,有数量,那元素的话,元素的名称包括元素的数量。

c语言深度剖析

c语言深度剖析

c语言深度剖析
C语言是一门广泛应用于计算机编程领域的高级编程语言,它的设计目标是提供一种能够以简洁的方式编写系统软件的语言。

C语言的出现极大地推动了计算机科学的发展,成为了现代计算机编程的基础。

在深度剖析C语言时,我们需要从以下几个方面进行分析:
1. 语言特性
C语言的语言特性包括数据类型、运算符、控制语句、函数等。

其中,数据类型是C语言的基础,包括整型、浮点型、字符型等。

运算符包括算术运算符、关系运算符、逻辑运算符等。

控制语句包括条件语句、循环语句等。

函数是C语言的重要特性,它可以将程序分解为多个模块,提高程序的可读性和可维护性。

2. 内存管理
C语言的内存管理是其最为重要的特性之一。

C语言中的内存分为栈、堆、全局变量等。

程序员需要手动管理内存,包括内存的分配和释放。

如果内存管理不当,会导致内存泄漏、内存溢出等问题,严重影响程序的稳定性和性能。

3. 指针
指针是C语言的重要特性之一,它可以让程序员直接访问内存中的
数据。

指针可以用于数组、函数、结构体等。

指针的使用需要注意指针的类型、指针的初始化、指针的运算等问题。

4. 预处理器
C语言的预处理器是其独特的特性之一,它可以在编译之前对源代码进行处理。

预处理器可以用于宏定义、条件编译等。

预处理器的使用需要注意宏定义的作用域、宏定义的参数等问题。

深度剖析C语言需要对其语言特性、内存管理、指针、预处理器等方面进行全面的分析和理解。

只有深入了解C语言的特性和使用方法,才能更好地应用C语言进行编程,提高程序的质量和效率。

c语言深度剖析

c语言深度剖析

c语言深度剖析“C语言深度剖析”是一本以C语言为主题的技术类著作,深入剖析了C语言的各个知识点,涵盖了从基础知识到高级应用的内容,并包含大量的实例和代码,是学习C语言编程的重要参考资料。

本书一共分为九章,其中前三章介绍了C语言的基础知识和语法规则,第四章介绍了C语言中的数据类型和运算符,第五章重点介绍了C语言中的控制结构,在第六章中讲解了C语言中的函数,第七章介绍了C语言中的指针,第八章介绍了C语言中的数组,第九章则从更深入的角度剖析了C语言中的各个部分,更加深入地讲解了C语言中的一些高级应用。

在学习C语言时,我们首先需要了解C语言程序的程序结构,这包括预处理器指令、程序主函数和程序的数据和算法等。

接着学习C 语言中各个数据类型的定义和使用,包括整型、浮点型、字符型等的变量定义和初始化方法,同时也要学习C语言中的各种运算符,如算术运算符、位运算符和逻辑运算符等。

接下来,我们需要学习C语言中的控制结构,包括if语句、while语句、for语句以及switch语句等,学习控制结构是学习C语言的重要一步。

在掌握C语言中的基础知识后,我们还需要学习C语言中的函数,了解函数的定义和调用方式,掌握C语言中函数的返回值以及函数参数的传递方式等。

在C语言中,指针是一项非常重要的知识点,学习C语言需要深入了解指针的概念及其使用方法,包括指针的定义、指针运算以及指针和数组的关系。

数组是C语言中另一个非常重要的知识点,我们需要了解C语言中数组的定义和使用,包括一维数组和多维数组的定义方法和使用方式。

最后,在深入剖析C语言的各个组成部分之后,我们需要对C语言进行更加深入的学习,学习C语言中的高级应用,包括结构体、共同体、文件操作、动态内存管理、函数指针等。

总之,“C语言深度剖析”为读者提供了一份全面深入的C语言学习资料,包含了许多实例和代码,可以帮助读者更好地掌握C语言编程的技能。

无论是初学者还是有经验的程序员,都可以从中获益匪浅。

C语言编译全过程剖析

C语言编译全过程剖析

C语言编译全过程编译的概念:编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。

编译的完整过程:C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf 等)1.编译预处理读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理伪指令主要包括以下四个方面:(1)宏定义指令,如#define Name TokenString,#undef等。

对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的 Name则不被替换。

对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。

(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。

这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。

预编译程序将根据有关的文件,将那些不必要的代码过滤掉(3)头文件包含指令,如#include"FileName"或者#include<FileName>等。

在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。

采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。

因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。

预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。

包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。

在程序中#include它们要使用尖括号(<>)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言深度解剖第一章:关键字1.1 定义声明Int i;定义创建了对象并为这个对象分配了内存Extern int i;声明没有分配内存。

1.2 auto在缺省的时候,编译器默认所以的变量都是auto的。

自动变量1.3 register 声明寄存器变量Register:这个关键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率。

(cpu:皇帝,寄存器:太监,内存:大臣,不考虑CPU的高速缓存区cache)寄存器的存取速度比内存块得多。

但在使用register修饰符也有些限制的:register变量必须是能被CPU寄存器所接受的类型。

这就意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度,而且register变量可能不存放在内存中,所以不能用取地址运算符“&”来获取register变量的地址。

1.4 static关键字2个作用:修饰变量、修饰函数。

第一个作用:修饰变量:局部变量和全局变量,存放于内存的静态区。

静态全局变量:作用域仅限于变量被定义的文件中,其他文件即使使用extern声明也没法使用它;要想在定义之前使用,就必须在前面加extern ***(故static声明的全局变量最好在文件顶端定义)。

静态局部变量:在函数体里面定义的,就只能在这个函数里用了,同一个文档中的其它函数也用不了。

由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值也不会被销毁,函数下次使用时任然能用到这个值。

例:#include<stdio.h>static int j;int k = 0;void fun1(void){static int i;i++;}void fun2(void){j++;}int main(void){for(k = 0;k<10;k++){fun1();fun2();}return 0;}解析:i、j看起来没有初始化,其实默认值为0.程序结束后i=10,j=10.第二个作用:修饰函数:成为静态函数,对函数的作用域仅限于本文件(所以又称内部函数)。

使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。

另static在C++里还有第三层含义。

1.4 sizeof关键字例:32位系统下#include <stdio.h>void fun(int b[100]){int a = sizeof(b);//a=4}int main(void){int *p = NULL;int length = sizeof(p);//length=4length = sizeof(*p);//length=4int a[100];length = sizeof(a);//length=400length = sizeof(a[100]);//length=4length = sizeof(&a);//length=400length = sizeof(&a[0]);//length=4fun(a);return 0;}1.5 -0与+0和补码signed char 为什么能表示的数据范围是-128~127答:一个char共8位可以表示256个数,最高位为符号位,除开最高位还有7位共128种编号,如果最高位为0,可以表示0(0 0000000)~127(0 1111111)共128个正整数;如果最高位为1,则可表示-128(1000 000)、-1(1000 0001)到-127(1 111 1111)共128个负整数,其实-128从数字大小来说应该为-0 ,但在数字世界里一般只需一个+0 ,即0 即可,-0最后就规定用来表示-128这个数了。

二进制数如何求补码:正数补码:全不变。

例:+1(0 000 0001)的补码(0 000 0001)。

负数的补码:除符号位外,各位取反加1例:-1(1 000 0001)的补码=(1 111 1110+1=1111 1111)。

Strlen函数判断一个字符串的结束就是以其末尾的'\0'为界限,不包括'\0'这个字符的。

头文件string.h1.6 float与“零值”比较Float与零值进行比较的if语句怎么写?Float a=0.0;If((a>=EPSINON)&&(a<=EPSINON));解析:EPSINON是定义好的精度,如果一个数落在【0.0- EPSINON,0.0+ EPSINON】这个闭区间内,则认为在某个精度内其值与零值相等。

有关于EPSINON这样的定义:const float EPSINON=0.00001; 《插入》:定义指针一定要初始化。

1.7constconst 是constant 的缩写,是恒定不变的意思,也翻译为常量、常数等。

很不幸,正是因为这一点,很多人都认为被const 修饰的值是常量。

这是不精确的,精确的说应该是只读的变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。

(1)c onst 修饰的只读变量:定义const 只读变量,具有不可变性。

例如:const intMax=100;intArray[Max];这里请在Visual C++6.0 里分别创建.c 文件和.cpp 文件测试一下。

你会发现在.c 文件中,编译器会提示出错,而在.cpp 文件中则顺利运行。

为什么呢?我们知道定义一个数组必须指定其元素的个数。

这也从侧面证实在C 语言中,const 修饰的Max 仍然是变量,只不过是只读属性罢了;而在C++里,扩展了const 的含义,这里就不讨论了。

注意:const 修饰的只读变量必须在定义的同时初始化。

(2)节省空间,避免不必要的内存分配,同时提高效率。

编译器通常不为普通const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。

例如:#define M 3 //宏常量const int N=5; //此时并未将N 放入内存中......int i=N; //此时为N 分配内存,以后不再分配!int I=M; //预编译期间进行宏替换,分配内存int j=N; //没有内存分配int J=M; //再进行宏替换,又一次分配内存!const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const 定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。

#define 宏是在预编译阶段进行替换,而const 修饰的只读变量是在编译的时候确定其值。

#define 宏没有类型,而const 修饰的只读变量具有特定的类型。

(3)修饰一般变量一般常量是指简单类型的只读变量。

这种只读变量在定义时,修饰符const 可以用在类型说明符前,也可以用在类型说明符后。

例如:int const i=2; 或const int i=2;(4)修饰数组定义或说明一个只读数组可采用如下格式:int const a[5]={1, 2, 3, 4, 5};或const int a[5]={1, 2, 3, 4, 5};(5)修饰指针const int *p; // p 可变,p 指向的对象不可变int const *p; // p 可变,p 指向的对象不可变int *const p; // p 不可变,p 指向的对象可变const int *const p; //指针p 和p 指向的对象都不可变在平时的授课中发现学生很难记住这几种情况。

这里给出一个记忆和理解的方法:先忽略类型名(编译器解析的时候也是忽略类型名),我们看const 离哪个近。

“近水楼台先得月”,离谁近就修饰谁。

const int *p; //const 修饰*p,p 是指针,*p 是指针指向的对象,不可变int const *p; //const修饰*p,p 是指针,*p 是指针指向的对象,不可变int *const p; //const修饰p,p 不可变,p 指向的对象可变const int *const p; //前一个const 修饰*p,后一个const 修饰p,指针p 和p 指向的对象都不可变(6)修饰函数的参数const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外改变时使用。

例如:void Fun(const int i);告诉编译器i 在函数体中的不能改变,从而防止了使用者的一些无意的或错误的修改。

(7)修饰函数的返回值const 修饰符也可以修饰函数的返回值,返回值不可被改变。

例如:const int Fun (void);在另一连接文件中引用const 只读变量:extern const int i; //正确的声明extern const int j=10; //错误!只读变量的值不能改变。

(8)完了吗?远没有。

在C++里,对const 做了进一步的扩展。

1.8最易变的关键字----volatilevolatile 是易变的、不稳定的意思。

volatile 关键字和const 一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。

遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

先看看下面的例子:int i=10;int j = i;//(1)语句int k = i;//(2)语句这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i 没有被用作左值。

这时候编译器认为i 的值没有发生改变,所以在(1)语句时从内存中取出i 的值赋给j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给k 赋值。

编译器不会生成出汇编代码重新从内存里取i 的值,这样提高了效率。

但要注意:(1)、(2)语句之间i 没有被用作左值才行。

再看另一个例子:volatile int i=10;int j = i;//(3)语句int k = i;//(4)语句volatile 关键字告诉编译器i 是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i 的地址处读取数据放在k 中。

这样看来,如果i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile 可以保证对特殊地址的稳定访问。

相关文档
最新文档