目录
4、把若干个目标文件、库文件合并成最终的可执行文件(默认名字a.out)
一、C语言介绍
丹尼斯.里奇和肯.汤普逊在1971~1973年美国贝尔实验室,在开发UNIX操作系统时,在BCPL语言的基础上(new B语言),发明第一款高级编程语言,取BCPL第二个字母作为名字,所以叫C语言。
它是为了开发操作系统而研发的一款编程语言,它特别擅长控制硬件,所以在服务器开发、驱动编程、单片机、嵌入式开发中使用较多
C语言的优点
1、语法简单、只有32个关键字、入门简单;
2、执行速度很快,可以媲美汇编语言的执行速度、适合用于执行实现算法、数据结构。
C语言的缺点
1、需要对内存、操作系统有一定的了解,易学难精;
2、由于出现时间过早,个人计算机没有普及,在设计时没有为普通人做太多的考虑,有一些语法上的陷阱和缺陷;
3、自由源于自律;
4、没有大型的软件商业公司在背后支持,可用的软件库较少。
二、第一个C程序
#include <stdio.h>
#include "stdio.h"
int main(int argc,const char* argv[])
{
printf("Hello World!\n");
return 0;
}
如何编译执行代码
在命令端口输入:
// 编译代码,生成可执行文件,如果代码没有错误,会生成 a.out 可执行文件
gcc xxx.c
// 执行程序
./a.out
// 合并执行
gcc xxx.c && ./a.out
详解Hello World
1、程序员所编写的代码并不是标准C代码,它需要经过一段程序把它翻译成标准C代码,负责翻译的程序叫做“预处理器”,被翻译的代码叫做“预处理指令”,所有预处理指令都是以“#”开头;
2、#include 是一条预处理指令,它的功能是导入一个辅助文件到当前文件中,以下为其写法
#include "filename.h"
// 先在当前工作目录下查找是否有filename.h这个文件,找到则直接导入,如果找不到,则再去系统指定路径查找并导入,如果还找不到则报错
// 一般用于导入自定义的头文件
#include <filename.h>
// 直接去系统指定路径查找并导入,如果找不到则报错
// 一般用于导入标准库的头文件
3、C语言标准委员会会给C语言以函数的形式提供了一些基础的功能,这些函数会被封装在libc.so库文件中,并且按照功能不同在库中分成了不同的头文件,例如:stdio.h、stdlib.h、string.h等;
4、stdio.h是负责对输入、输出数据进行功能实现,当程序需要使用输入、输出数据时,需要导入该头文件;
5、在C语言,通过函数(function)来管理代码的最小单位,一个函数就是一段具有某一项功能的代码块,main函数是C语言程序的默认的执行入口,入口必须有且只有一个,无论它定在任何位置都最先执行;
6、函数名后面的内容是函数的调用者传递给该函数的一些数据;
7、函数名前面是一种数据类型,它表示该函数的执行结果是什么类型的数据,int表示main函数的执行结果是整数;
8、C语言是使用大括号开分隔代码区域,被大括号包含的代码都属于该函数;
9、printf/scanf 属于标准库的函数,用于输出、输入数据,还可以用于调试代码;
转义字符
在输出数据时,键盘上有一些字符无法直接表示,通过转义字符来表示这些特殊字符
\n | 换行 |
\b | 退格键 \b \b 可以模拟backspace的效果 |
\\ | 显示一个\ |
%% | 显示一个% |
\r | 回到行首 |
\t | 制表符,相当于tab键 |
\a | 铃响 |
10、return的两项功能:
1、直接结束整个函数的执行,当执行到return语句时,哪怕后面还有代码也不会执行
2、还可以返回一个数据给函数的调用者,main函数的调用者是操作系统
11、main函数的返回值表示该程序结束时的状态:
return 正数 表示程序执行出现异常 (别人的错)
return 0 表示程序正常结束
return 负数 表示程序执行出现错误 (自己的错)
echo $? 查看最后一个程序的main函数的执行结果
12、C语言以分号作为一行代码的结束标志,如果代码过长可以换行
13、C语言的语法标准:
C89语法标准,是C语言的第一套语法标准
C99语法标准,对C89的升级、扩展、增强,我们的系统默认使用的标准
通过 编译参数 -std=gnu89\99 更改编译的语法标准
C11语法标准,全新的升级
三、编译器和gcc
1、什么是编译器
它是一个负责编译代码的程序,它负责把人能看得懂的代码(文本文件)翻译成计算机能看懂的二进制指令,它由预处理器、编译器、汇编器、链接器组成,统称编译器
gcc是由GNU组织为了编译Linux内核而开发的一款C语言编译器,嵌入式开发使用的是 arm-linux-gcc(交叉编译器)
2、gcc编译器把C代码变成可执行程序的过程
1、把程序员所编写的代码进行预处理
// 把预处理的结果直接显示到屏幕上
gcc -E filename.c
// 会生成以.i结尾的预处理文件
gcc -E filename.c -o filename.i
2、把预处理的结果翻译成汇编代码
// 会生成以 .s 结尾的汇编文件
gcc -S filename.i
3、把汇编代码翻译成二进制指令
// 会生成以 .o 结尾的目标文件
gcc -c filename.s
4、把若干个目标文件、库文件合并成最终的可执行文件(默认名字a.out)
合并链接若干个目标文件,生成a.out可执行文件
gcc aa.o bb.o cc.o ...
// 合并链接若干个目标文件,生成名为filename可执行文件
gcc aa.o bb.o cc.o ... -o filename
**注意**:gcc filename.c 就包含了以上四个步骤,目前了解这些步骤为了后序学习预处理指令、多文件编程、静态库、共享库打下基础
3、gcc、arm-linux-gcc编译器常用的参数
-E | 预处理 |
-S | 生成汇编文件 |
-c | 生成目标文件\只编译不链接 |
-o | 设置编译结果的名字 |
-I | 设置要导入的头文件的路径 <> "" |
-l | 设置要链接的库名,例如:使用sqrt、pow等数学函数时就需要链接数学库 -lm |
-L | 设置要链接的库的路径,一般用于连接第三方库,或自定义的库 |
-D | 在编译时定义宏 |
-g | 编译时添加调试信息,这样编译出的程序可以用gdb调试 |
-Wall | 显示所有警告,编译器会以更严格的标准检查代码 |
-Werror | 把警告当错误处理 |
-std | 指定编译器要遵循的语法标准,c89,c99,c11,当前系统默认的是c99标准 |
4、C语言的文件类型(了解)
.h | 头文件,里面是一些对.c文件的说明 |
.c | 源文件,里面是一些功能型代码 |
.i | 预处理文件 |
.s | 汇编文件 |
.o | 目标文件 |
.gch | 头文件的编译结果,用于检查自定义的头文件是否有语法错误,建议立即删除 gcc -c xxx.h |
.a | 静态库文件,相当Windows系统下的.lib文件 |
.so | 动态库文件,相当Windows系统下的.dll文件 |
四、C语言中基础的数据类型
C语言为什么要把数据分成不同的类型
数据存储在计算机中需要耗费存储空间(内存、硬盘),在编程语言中把数据按照实际需要:范围、特点划分成不同的种类,解决什么问题就使用合适的类型,这样可以节约存储空间、提高运算速度,因此这是程序员的基本功,对于嵌入式开发这点尤为重要。
C语言中数据类型分为两大类:自建类(程序员自己设计的类型:结构、联合、类C++)、内建类(C语言自带的类型)
存储空间的单位
Bit 比特\比特位\位 | 一个bit存储一个0\1 计算机中的存储数据的最小单位 |
Byte 字节 | 存储8个比特 计算机中存储数据的基本单位 |
Kb | 1024字节 |
Mb | 1024Kb |
Gb | 1024Mb |
Tb | 1024Gb |
Pb | 1024Tb |
整型
有符号整型
最高位的二进制位用于表示0正数、1负数
由于有符号整数使用频繁,所以编译器默认signed可以不加,不加就代表了加
类型名 | 所占用字节数 | 取值范围 |
---|---|---|
char | 1 | -128~127 |
short | 2 | -32678~32767 |
int | 4 | -2,147,483,648~2,147,483,647 |
long | 4/8 | |
long long | 8 | -9,223,372,036,854,775,808~9,223,372,036,854,775,807 |
注意:signed long的字节数取决于从操作系统的位数 32位下是4 64位是8
无符号整数
所有的二进制位都用来表示数据,只能表示正数
类型名 | 所占用字节数 | 取值范围 |
---|---|---|
unsigned char | 1 | 0~255 |
unsigned short | 2 | 0~65535 |
unsigned int | 4 | 0~4,294,967,295 |
unsigned long | 4/8 | |
unsigned long long | 8 | 0~18,446,744,073,709,551,615 |
注意:unsigned long的字节数取决于从操作系统的位数 32位下是4 64位是8
无符号类型一般用于计数,unsigned不能省略,使用会比较麻烦,C语言标准库为了让我们使用简单,在<stdint.h>头文件中对这些类型名进行重定义
uint8_t uint16_t uint32_t uint64_t
int8_t int16_t int32_t int64_t
size_t time_t
浮点型
小数点是浮动的,也就是带有小数部分的数据,采用科学计数法存储数据,由符号位+指数域+小数域组成,这种存储格式,导致存储速度、运行速度比整数要慢得多,又不太准确,所以尽量不使用
类型名 | 所占用字节数 |
---|---|
单精度 float | 4 |
双精度 double | 8 |
高精度 long double | 12\16 |
注意:编译器只对小数点后六位有效
字符型
char字符型,字符就是符号或图案,但是在计算机中都是只能以整数存储(以整数来模拟字符),当需要显示成字符时,会根据ASCII表中的对应关系显示出相应的符号或图案
字符 | ASCII值 |
---|---|
'0' | 48 |
'A' | 65 |
'a' | 97 |
'\0' | 0 结束标志 |
bool布尔型
C语言没有真正的布尔类型,先有的C语言后才出现的布尔类型,在C89之后使用类似打补丁的方式增加布尔类型,需要包含<stdbool.h>
类型名 | 所占用字节数 |
---|---|
bool | 1字节 |
true | 4字节 实际就是整数1 |
false | 4字节 实际就是整数0 |
注意:bool类型也是使用整型模拟的
注意:一般用于表示只有两种状态(对\错)的数据
五、变量
在程序运行过程中可以变化的数据,它就是存储数据的容器,需要先定义才能使用
定义变量
数据类型 <变量名>;
1、变量所占用的内存字节数、存储数据的范围、使用的规则都由变量的数据类型决定。并且确定后无法改变
2、变量名也叫做标识符,变量的定义本质上就是操作系统把一个标识符与内存之间建立一种映射关系,操作系统不会对映射好的内存进行初始化清理,所以**变量的默认值是不确定**,所以我们要对一些有特殊用途的变量必须进行初始化,例如:求和、计数、平均值、累加。
3、定义好的变量,出了它所在的大括号就不能再使用了。
变量名的取名规则
1、必须由数字、字母、下划线组成
2、必须不不能以数字开
3、必须不能与C语言32关键字重名
合法:printf scanf num_1 true bool
非法:32_num *num
4、见名知意,了解类型、功能、作用范围、归属模块
变量的使用
num = 10; // 被赋值,存储数据、修改数据,当成容器使用
num*3/4; // 参与运算,此时变量名代表它存储的数据
变量的输出
#include <stdio.h>
int printf(const char *format, ...);
功能:它C标准库函数,把若干个数据输出显示到屏幕终端上
format:"提示信息+变量的类型信息+转义字符"
...: 可变长参数,若干个变量名,变量名之间使用逗号隔开
返回值:表示printf输出到终端上的字符个数 一般不会用
在C语言中使用占位符来表示变量的类型:
%hhd %hd %d %ld %lld 有符号整型的占位符
%hhu %hu %u %lu %llu 无符号整型的占位符
%f %lf %LF 浮点型的占位符
%c 字符型的占位符
注意:布尔类型用于逻辑运算的,不参与输入、输出,没有专属的占位符,如果想要强行输入输出、当成整数处理即可(0\1)