C语言

74 阅读9分钟

一.  GCC编译C/C++的四个过程


预处理

gcc -E main.c -o main.i

编译阶段

gcc -S main.i -o main.s

汇编阶段

gcc -c main.s -o main.o

链接阶段

gcc main.o -o main.exe

二.  C 中的变量声明


变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。

变量的声明有两种情况:

1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。

2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。除非有extern关键字,否则都是变量的定义。

        extern int i; //声明,不是定义 

        int i; //声明,也是定义

三.  C 存储类


auto 是局部变量的默认存储类, 限定变量只能在函数内部使用;

register 代表了寄存器变量,不在内存中使用;

static是全局变量的默认存储类,表示变量在程序生命周期内可见;

extern 表示全局变量,即对程序内所有文件可见,类似于Java中的public关键字;

  •  C 语言中全局变量、局部变量、静态全局变量、静态局部变量的区别

从作用域看

1、全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

2、静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

3、局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

4、静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

从分配内存空间看:

1、全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

2、全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

  • 1) 静态变量会被放在程序的静态数据存储区(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
  • 2) 变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。

Tips:

  • A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
  • B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
  • C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
  • D.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带"内部存储器"功能的的函数)
  • E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针

四.  从两个例子分析C语言的声明


在C语言中,声明的形式和使用的形式相似,这种用法可能是C语言的独创,K & R也承认"C语言声明的语法有时候会带来严重的问题"。C语言的声明存在的最大问题是你无法以一种人们所习惯的自然方式从左到右阅读一个声明。下面看一个例子:

char * const *(*next)();

如果在第一眼就能看出这个声明要表达的意思,那么证明你的C语言功底已经到了一定的程度。《C专家编程》一书中给出的识别步骤为:

  1. 从变量名next开始,并注意到它直接被括号括住;
  2. 所以先把括号里的东西作为一个整体,得出"next”是一个指向... 的指针;
  3. 然后考虑括号外面的东西,在星号前缀和括号后缀之间做一个选择;
  4. 根据C语言声明的优先级规则(后面会给出),优先级较高的是右边的函数括号,所以得出"next"是一个函数指针,指向一个返回 ...的函数;
  5. 然后,,处理前缀"*",得出指针所指的内容;
  6. 最后,把"char * const *"解释为指向字符串的常量指针。

把上述结果加以概括,这个声明表示"next是一个指针,它指向一个函数,这个函数返回另一个指针,该指针指向一个类型为char的常量指针"。这个问题便迎刃而解了.

下面再看一个例子:

char *(* c[10])(int **p);
void (*signal(int sig,void(*func)(int)))(int)

首先,从变量名c开始,然后处理后缀"[]",表明c是一个数组,接着处理前 缀"*",表示c是一个指针数组。然后处理后面的括号,表明数组c中的指针类型 是指向一个函数的指针,并且这个函数的参数有且仅有一个:为指向指针的指 针,该函数的返回值为一个指向字符串的指针。归纳在一起,为: "c是一个数组[0...9],它的元素类型是函数指针,其所指向的函数返回值是一个 指向字符串的指针,并且把一个指向指针的指针作为唯一的参数"。 以下是《C专家编程》一书中提到的C语言声明的优先级规则,摘自第64页。

eg

数组指针: int (*p)[5] 这里的p是一个指针,指向一个具有5个元素的数组指针
指针数组: int p[5] 这里的p是一个数组,数组中的元素类型是int

C语言——常量指针和指针常量的区别


常量指针:表示const修饰的为所申明的类型。 例如:

//注意char const *p与const char *p效果相同。
void consttest(const char *p) {
    printf("p[1]=%c\n",p[1]); 
    p=1;//正确 
    *(p+1)='a';//错误
}

因为const修饰的是char,所以就是说:p所指向的内存地址所对应的值,是 const,因此不可修改。但指针所指向的内存地址是可以修改的,因为其并不是 const类型。

指针常量:表示const修改的指针。例如:

void testconst(char *const p)
{
char *tmp="13213"; p=1;;//错误 
p=tmp;;//错误 
p[1]='a';//正确
*(p+1)='a';//正确
}

因为const修饰的是指针p,也就是说:指针所指向的内存地址是const,不可修 改。但p所指向内存地址所对应的值是可以修改的,因为其并不是const类型。

指向常量的指针常量: const同时修饰类型和指针。只读 例如:

void consttestconst(const char *const p) //引用 
{ 
    p=1;//错误 
    p[1]='a';//错误 
}

因为const同时修饰这类型和指针,也就是说:指针所指向的内存地址不可修改 同时内存地址所对应的值也不可修改。

总结:主要看的就是const所处的位置。

  • 1)const 在前:表示const修饰的为所申明的类型。常量指针
  • 2)const 在后:表示const修饰的为指针。指针常量
  • 3)前*后均有:表示const同时修改类型和指针。指向常量的指针常量

const的优点 在C/C++中关键字const用来定义一个只读的变量或者对象,有如下 优点:

  • (1)便于类型检查,如函数的函数 fun(const int a) a的值不允许变, 这样便于保护实参。
  • (2)功能类似与宏定义,方便参数的修改和调 整。如 const int max = 100;
  • (3)节省空间,如果再定义a = max,b=max。。。就不用在为max分配空间了,而用宏定义的话就一直 进行宏替换并为变量分配空间
  • (4)为函数重载提供参考

常量指针和指针常量的区别 下面通过一个例子来解析 常量指针 和 指针常量,我 们先总结一下 常量指针 和 指针常量 的区别

首先一定要明白哪种定义方式是常量指针,哪种是指针常量,这里可以记住三句 话加深记忆:

(指针)和 const(常量) 谁在前先读谁 ;*象征着地址,const象征着内 容;谁在前面谁就不允许改变。