
局部变量用static声明,则使该变量在整个程序执行期间不释放,分配的内存单元始终存在。
外部变量用static声明,则该变量只能在本文件中使用,而不能在其他文件中使用。
extern inline函数允许和全局函数重名,可以在文件范围内替代外部定义的全局函数。 在②处调用cels的时候编译器可能选择用本文件内的inline版本,也有可能跑去调用外部定义的cels函数(c99没有规定此时的行为,不过编译器 肯定都会尽量使用文件内定义的inline版本,要不然inline函数就没有存在的意义了)。宏替换,使用函数体替换调用处的函数名,一般在代码中用inline修饰,但是是否能行成内联函数,需要看编译器对函数定义的具体处理显式内联函数:在类内部声明c语言 函数 内联,在类外部定义隐式内联函数:在类声明的内部定义引入内联函数是为了解决函数中程序调用的效率问题,这个就需要知道函数调用的原理了,函数调用实际上是将程序执行顺序转移到函数所存放的内存中的某个地址,将函数的程序内容执行完后,再返回到调用该函数的地方去。
内部函数:一个函数只能被本文件中其他函数所调用,称为内部函数,定义时,函数类型前面加上static,即:static int fun(int a,int b); 内部函数由称为静态函数,作用域只限于所在文件,在不同的文件中有同名的内部函数,互不干扰。
外部函数:定义时加上extern,可供其他函数调用。
4、堆和栈的比较
--- 申请方式:
stack -由系统自动分配(局部变量)

heap - 需要程序员自己申请,并指明大小(malloc/new)
--- 申请后系统的响应
stack - 只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
heap - 首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
--- 申请大小的限制
这样的话,我们开辟char* 类型的堆内存空间,它会有一串的栈内存空间来存放你的门牌号,也就是开辟这些指针的地址,但并没有开辟栈内存空间,而是程序自己在运行的时候开辟了一串的内存空间来存放指针的地址,也就是门牌号。这些段在内存中分配位置,跟硬件架构和操作系统都有关系,x86中栈都是由高地址向低地址分配,堆是由低地址向高地址分配,不过在 windows 和 linux 中堆和栈的位置相反,另外存放静态数据、代码的区域位置也有一些不同(我是在《c和c++安全编码》上看到的,具体细节记不清了,现在不在学校,网上搜了好久也没有见到图,所以就不贴图了)。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在windows下栈的大小是固定的空间(1m或2m)超过栈的剩余空间会提示overflow。
上图还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。元素有放入顺序,元素可重复 list接口有三个实现类:linkedlist,arraylist,vector linkedlist:底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。
--- 申请效率的比较

栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由malloc/new分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。
另外,在Winodws下,最好的方式是用VirtualAlloc分配内存,它不是在堆内,也不在栈内,是直接在进程的地址空间中保留的一块内存。虽然用起来最不方便,但是速度快,也最灵活。
--- 存储内容的比较
栈:在函数调用时,第一个进栈的是主函数中的下一条指令的地址(函数调用语句的下一条可执行语句的地址),然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
3.递归效率不高,递归层次过多导致栈溢出(在计算机中,函数调用是通过栈(stack))这种数据结构实现的c语言 函数 内联,每当进入一次函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层。调用时输入23和24.5,输入的这2个参数才是真正需要传递给函数的参数,ref int, ref double是告诉alien需要分配空间,调用c函数从栈中获取它的参数,调用结束后将返回结果放到栈中(为了区分返回结果和栈中的其他的值,每个c函数还会返回结果的个数),然后lua函数返回结果值。以上栈信息基本具备了错误栈信息的所有性质. 初看像是堆破坏, 因为运行时的堆分配与释放函数出现在了栈中. 但如果我们再想想就会发现 heapfree 函数不应调用 heapalloc 函数, 而接下来更不应该调用 getfullpathname. 所以这个栈信息是无意义的.。
栈空间是由编译器自动管理的,不用程序员操心。 堆是动态分配内存的,并且你可以分配使用很大的内存,但是用不好会产生内存泄漏。并且频繁的malloc和free会产生内存碎片(有点类似磁盘碎片),因为C分配动态内存时是寻找匹配的内存的。而栈则不会产生内存碎片,在栈上存取数据比通过指针在堆上存取数据快些。一般大家说的堆栈就是指栈(stack),而说堆时才是堆(heap)。栈是高地址向低地址生长。

5、volatile的问题
volatile的意思是易变的,一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。精确的说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。用volatile变量的例子:
--- 并行设备的硬件寄存器(如状态寄存器)
--- 一个中断服务子程序中会访问到的非自动变量
--- 多线程应用中被几个任务共享的变量。
----- 一个参数既可以是const还可以是valatile的吗?
可以的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
----- 一个指针可以是volatile的吗?

可以的。尽管这并不是很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针。
6、const用途
--- 可以定义const常量
--- 可以修饰函数的参数,返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
在函数的形参前加const关键字意味着这个参数在函数体内不会被修改,属于“输入参数”。
const意味着“只读”。 const int a; 等同于 int const a; //a是一个只读整型变量
//一个指向指针的的指针,它指向的指针是指向一个整型数。其表示声明了一个指向整型常量的指针,可以修改指针的值(其他变量的地址),但是不能修改它指向的值。看到这个我们会联想到const分别修饰指针变量和指针指向的内容,就像语句(3)和语句(4),语句(3)表示指针指向的对象的内容不能改变,只要是他指向的内容就是一个只读变量,语句(4)表示指针的值,也就是地址不能改变。
int * const a; //a是常指针,指向不可以改变,指向的值可以改变
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-109566-1.html
我们也派军舰到他家去吧