GCC
谈到 GCC,就不得不提 GNU 计划。GNU 全称 GNU’s Not UNIX,又被称为“革奴计划”,由理查德·斯托曼于 1983 年发起。GNU 计划的最终目标是打造出一套完全自由(即自由使用、自由更改、自由发布)、开源的操作系统,并初步将其命名为 GNU 操作系统。早期 GCC 的全拼为 GNU C Compiler,即 GUN 计划诞生的 C 语言编译器,显然最初 GCC 的定位确实只用于编译 C 语言。但经过这些年不断的迭代,GCC 的功能得到了很大的扩展,它不仅可以用来编译 C 语言程序,还可以处理 C++、Go、Objective -C 等多种编译语言编写的程序。与此同时,由于之前的 GNU C Compiler 已经无法完美诠释 GCC 的含义,所以其英文全称被重新定义为 GNU Compiler Collection,即 GNU 编译器套件。

GCC编译过程
预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法
编译:检查语法,将预处理后文件编译生成汇编文件
汇编:将汇编文件生成目标文件(二进制文件)
链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中
分步编译
预处理:gcc -E hello.c -o hello.i
编 译:gcc -S hello.i -o hello.s
汇 编:gcc -c hello.s -o hello.o
链 接:gcc hello.o -o hello
| 选项 | 含义 |
|---|---|
| .c | C语言文件 |
| -E | 预处理 |
| .i | 预处理后的C语言文件 |
| -S | 预处理和编译 |
| .s | 编译后的汇编文件 |
| -c | 预处理,编译,汇编 |
| .o | 汇编后的目标文件 |
| .o file | 指定生成的文件,名为file |
一步编译
gcc hello.c -o hello(还是经过:预处理、编译、汇编、链接的过程)
C语言常见错误
编译型错误
这类问题往往是语法错误导致的。如:逗号的使用,分号的添加,括号的对应,各类操作符的使用,库函数的使用格式,各类循环的使用格式,数组的初始化,等等。遇到此类问题我们只需按照错误列表的提示,对应项目位置,文件位置及行号,找到错误所在,按照提示添加或修改即可。
链接型错误
此类问题也比较容易解决,往往是标识符未定义引起的。如:变量、常量和宏的定义,头文件的包含,文件的引入,库函数名的拼写,自定义函数名的一致,等等。
运行时错误
此类问题就要花费点时间去解决了,往往涉及到底层原理,数据结构等相关知识。如:指针的越界访问,栈溢出,逻辑的漏洞,未初始化的变量,数组越界,字符串溢出,重复释放内存,使用无效的指针,递归函数的限制,等等。此类问题就要经过不断调试及思考,一步一部判断问题所在,可借助编译器中的调试工具,如断点、监视、内存,反汇编等,并配合快捷键高效改错。
C语言预处理
#include
包含头文件
#define
替换作用,不进行语法检查,在编译时,对宏不进行语法检查,直接替换
1.宏定义
#define 宏名 宏体 (加括号避免逻辑错误),此时容易产生逻辑错误,所以我们一般给宏体添加括号,避免逻辑错误。
#include <stdio.h>
#include <stdlib.h>
#define A(x) (x*3)
int main()
{
printf("%d\n",A(3));
printf("Hello world!\n");
return 0;
}
2.宏函数
#define 宏函数名(x) 宏函数体
对于宏这种类型,还有一个知识点,宏展开下的#,##
#字符串化
##连接符号
#include <stdio.h>
#define A(x) #x
#define DAY(x) myday##x
int main()
{
int myday1=10;
int myday2=20;
printf(A(ab\n));
printf("the day is %d\n",DAY(1));
printf("the day is %d\n",DAY(2));
return 0;
}
3.预定义宏
预定义宏是头文件中已经定义过的宏:
FUNCTION :函数名
LINE :行号
FILE :文件名
#include <stdio.h>
int main()
{
printf("文件名:%s,函数名:%s,行号%d\n",__FILE__,__FUNCTION__,__LINE__);
return 0;
}
条件编译 #ifdef #else #endif
#ifdef 宏名(宏名是否定义)
语句一
else
语句二
#endif
#include <stdio.h>
#define star
int main()
{
#ifdef star
printf("已经定义\n");
#else
printf("未定义\n“);
#endif // star
printf("hello world\n");
return 0;
}
C语言关键字
C语言的关键字总共有32个,分别是 :
auto double int struct break else long switch
case enum register typedef char extern return union
const float short unsigned continue for signed void
default goto sizeof volatile do if while static
1.数据类型关键字
基本数据类型(5个):
> void:声明函数无返回值或无参数,声明无类型指针,
> char:字符型类型数据,char类型是个1字节,它的取值范围是[-128,127] (-2^7-2^7-1)
> int:整型数据,int类型为4个字节,它的取值范围是[-2147483648,2147483647] (-2^31-2^31-1)
> float:单精度浮点型数据,float类型为4个字节,它的数值取值范围为[-3.4*10^-38 ~ 3.4*10^38]
> double:双精度浮点型数据,double类型为8个字节,它的取值范围为[-1.7*10^-308 ~ 1.7*10^308]
类型修饰关键字(4个):
> short:修饰int,短整型数据,可省略被修饰的int,short类型为2个字节,它的取值范围是
[-32768 , 32767] (-2^15 - 2^15-1)
> long:修饰int,长整形数据,可省略被修饰的int,long int类型为4个字节。它的取值范围是
[-2147483648 , 2147483647] (-2^31 - 2^31-1)
> signed:修饰整型数据,有符号数据类型,编译器默认数据为signed类型(char类型数据除外)
> unsigned:修饰整型数据,无符号数据类型,被unsigned修饰的变量,其取值范围一定是大于0的。
1、无符号整形 unsigned int 4字节 0 ~ 4294967295
2、无符号短整型 unsigned short int 2字节 0 ~ 65535
3、无符号长整形 unsigned long int 4字节 0 ~ 4294967295
4、无符号字符型 unsigned char 1字节 0 ~ 255
复杂类型关键字(5个)
> struct:结构体声明
> union:共用体声明
> enum:枚举声明
> typedef:声明类型别名
> sizeof:得到特定类型或特定类型变量的大小
存储级别关键字(6个)
> auto:指定为自动变量,由编译器自动分配及释放。如果在括号内,通常在栈上分配
> static:指定为静态变量,分配在静态变量区,修饰函数时,指定函数作用域为文件内部
> extern:指定对应变量为外部变量,即在另外的目标文件中定义,可以认为是约定由另外文件声明
> const:与volatile合称“cv特性”,指定变量不可被当前线程/进程改变
> register:这个关键字请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问以提高效率
2.流程控制关键字
分支结构(5个)
> if:条件语句 else:条件语句否定分支(与if连用)
> switch:开关语句(多重分支语句)
> case:开关语句中的分支标记
> default:开关语句中的“其他”分治,可选
循环结构(3个)
> for:for循环结构,for(1;2;3)4;的执行顺序为1->2->4->3->2...循环,其中2为循环条件
> do:do循环结构,do 1 while(2);的执行顺序是1->2->1...循环,2为循环条件
> while:while循环结构,while(1) 2;的执行顺序是1->2->1...循环,1为循环条件
以上循环语句,当循环条件表达式为真则继续循环,为假则跳出循环。
跳转结构(4个)
> return:用在函数体中,返回特定值(或者是void值,即不返回值)
> continue:结束当前循环,开始下一轮循环
> break:跳出当前循环或switch结构
> goto:无条件跳转语句
C语言运算符
算术运算:+ - * / %
逻辑运算:|| && > >= < <= ?= !
位运算:<< >> & | ^ ~
A&0:清零
A&1:取出
A|0:保留
A|1:设置为高电平
赋值运算:= += -= &=
内存访问符号:() [] {} -> . * &
C语言指针
1.指针是什么
指针是包含内存地址的变量,这个地址是内存中另一个对象(通常是另一个变量)的位置。例如如果一个变量包含另一个变量的地址,我们说第一个变量指向第二个变量。
指针的大小:在32位系统中,指针的大小是4字节。在64位系统中,指针的大小是8字节
#include <stdio.h>
int main(void)
{
int *p;
printf("sizeof:%d",sizeof(p));
return 0;
}
结果:sizeof:8
1、在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,
所 以一个指针变量的大小就应该是4个字节。
2、在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址指针的
大小在32位平台是4个字节,在64位平台是8个字节。
指针所指的大小:与指针的声明相关,(int *p)为4字节 (char *p)为1字节
#include <stdio.h>
int main(void)
{
int *p;
printf("sizeof:%d",sizeof(*p));
return 0;
}
结果:sizeof:8
2.指针与修饰符
指针+const
常量指针。
常量是形容词,指针是名词,常量指针本质是指针,(1)const int *p;(2)int const *p;
指针常量。
指针是形容词,常量是名词。指针常量的本质是一个常量,(1)int *const b (2)int *b const
常量指针所指向的地址可以改变,地址里的内容不能改变。指针常量所指向的地址不能改变,但是地址里的内容可以改变。
3.指针与数组
数组指针
定义:是指一个指向数组的指针,它其实还是一个指针,指向数组的指针
int (*p)[10]; //其中,由于[]的优先级高于*,所以必须添加(*p).
指针数组
定义:是指一个数组里面装着指针,也即指针数组是一个数组,内含指针
int *a[10]; //指针数组的定义形式;
4.指针与函数
指针函数
指针函数: 就是一个返回指针的函数 ,它的本质是一个函数,不过它的返回值是一个指针。
int *fun(int x,int y);
函数指针
函数指针:函数指针 的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针。
int (*fun)(int x,int y);
463

被折叠的 条评论
为什么被折叠?



