c 语言编译
编译型语言:通过编译器编译源代码文件生成机器能够识别可执行文件/二进制
编译器名字 gcc,arm-linux-gcc, arm-none-linux-gnueabi
可通过 gcc -v 查看编译器是否存在
缺省状态:编译器名字 源代码文件名字
eg:gcc hello
命令格式:
编译器名字 源代码文件名字 指定参数(-o) 生成的程序文件名字
eg:
gcc hello.c -o hello
gcc hello.c --会默认生成 Linux 可执行程序 a.out
在Windows中则是 a.exe
通过./a.out执行文件
make
可以通过构建工具(make),直接选择依赖条件/规则来编译
# 假设有 hello.c 文件,如果想要使用构建工具进行编译,安装构建工具
sudo apt install make
1. 编译(make 后面的参数是用来指定从当前查找以用户指定的这个名字前缀的c源代码文件) make hello
2.执行
# . 当前路径上找一个即将要执行的程序
# / 路径拼接符
./hello
.\hello.exe # 后缀不能少,因为Windows就是以后缀来区分文件类型
查看文件属性
file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=2500b0e3243b8052a5cdb06925e15447ea54c4ba, not stripped
x86-64---》该程序可以运行在 x86-64 平台
ubuntu linux ARM ---> 开发板
ELF ---》二进制文件格式
编译过程做什么事情
检查语法
编译之后的表现
1)编译通过
编译之后没有任何提示,说明 编译完美通过,生成一个可执行程序。
2)编译警告
编译之后会出现warning提示,还是可以生成一个可执行程序。比如头文件 没写
警告虽然不代表出错,有些警告可以忽略,但是有些警告不能忽略
3)编译出错
语法出错,会有一个明显的提示error,根据提示出错的信息找到问题所在
注意:
- 如果使用缺省参数进行编译,则要明确,运行时的程序是(Linux:a.out/Window:a.exe),但如果使用指定参数进行编译,则必须要明确的程序名字是-o参数后面程序文件名字
C 程序
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
这段代码是一个C语言程序。让我们一步步来了解它:
- #include : 这是一个预处理指令,它告诉编译器在编译之前包含标准输入输出库的内容,这样我们就可以使用其中的printf函数。
- int main(void): 这是主函数,所有的C程序都必须有且只有一个main函数作为程序的入口。返回类型int表示函数执行后返回一个整数值,void表示这个函数不接受任何参数。
- printf("Hello, World!\n");: 这是一个库函数printf的调用,它的作用是向屏幕输出一段文字。"%s"表示输出字符串,\n表示换行符。
- return 0;: 这是main函数的返回语句,它表示程序正常结束,并返回给操作系统一个整数值0,通常表示程序成功执行。
头文件
#include <stdio.h>
- C语言程序中,任何符号(包括变量和函数)的使用,都是需要提前声明的。
- 如果程序用到了系统库函数,那么就需要包含相应的系统头文件来进行声明。
- 上述代码中用到了库函数 printf ,而这个函数的声明在头文件 stdio.h 中,因此在该程序中需要包含此头文件。
声明
概念:对源文件外定义的某个符号进行描述的过程,称为声明
作用:经过声明的符号,编译器才能正确识别和编译,否则编译器不认识,无法判定语法错误
符号:变量、函数等
示例:
// 声明一个变量符号number
int number = 100;
// 声明一个函数符号function
void function(int size, char *buf);
主函数
- 主函数是必须有的,每一个C语言程序有且仅有一个main函数,哪怕是空的。
- 主函数的名字是固定的,叫 main ,这个函数名不可被挪作他用。
- 主函数是程序的入口,也就是程序开始运行的地方。
- 主函数分解如下:
// int: 返回值类型,代表主函数最终的执行结果是一个整型数据
// main(void): main是函数名,这个名字不能变
// void是函数参数列表,可以省略 int main(void) { }
在 Linux 环境下,主函数 main 根据程序最终是否需要接收外部命令行参数,实际上有两个版本:
// 不接收外部命令行参数的版本 int main() { ... }
// 接收外部命令行参数的版本 int main(int argc, char **argv) { ... }
printf函数
它的功能就是:向终端输出一段指定格式的数据。
// 向终端输出一段字符串
printf("Hello World!\n");
格式输出控制符
- 概念:函数 printf被称为格式化IO函数, 因为它是按照指定格式来操作数据的。以常见的整数、浮点数和字符串为例,printf 函数相关的控制格式符如下所示:
// 格式化输出函数 printf();
printf("格式化控制符", 数值);
// 根据需要输出不同格式的数据
printf("%d\n", 100); // 输出1个整数
printf("%d, %d\n", 100, 200); // 输出2个整数
printf("%f\n", 3.14); // 输出浮点数
printf("%c\n", 'x'); // 输出字符
printf("%s\n", "abcd"); // 输出字符串
printf("a=%d, %s\n", "abcd"); // 输出字符串
%u --->unsigned int
%hu half unsigned int
%hhu half half unsigned int
语法点:
- 类似 %d、%f 被称为格式控制符
- 一个格式控制符对应一个数据
- ‘\n’ 是一个字符,表示回车符
格式控制符:
- 十进制整数:%d
- 八进制整数:%o
- 十六进制整数:%x
- 字符:%c
- 字符串:%s
- 单精度浮点数:%f
- 双精度浮点数:%lf
- 长双精度浮点数:%Lf
- 地址:%p
4.return语句
C语言中的关键字 return 的含义是结束一个函数,并返回某个数据(若有)。而具体到 main 函数中时,由于主函数 main 的结束同时也意味着整个程序的结束,因此在上述 Hello World 程序中 return 后整个程序就退出了
一般而言,程序正常退出时,main函数返回值是0;当程序异常退出时,main函数返回值是非0。
注意:main函数的返回值是给上一级进程的,因此理论上讲在当前的单进程程序中,main函数的返回值究竟是多少都无所谓,因为根本没有去使用这个返回值,除非在多进程程序中,进程间才需要使用main函数的返回值来传递信息。
数据类型
概述
很多时候,我们编写程序的目的是让计算机能够帮助我们去处理数据。
计算机要处理的数据(诸如数字、字符串、文字、符号、图形、音频、视频等)是以二进制的形式存放在内存中的。
而且在程序中数据是有类型区分,通常分为整型、浮点型、字符串等等。数据类型其实是固定大小内存的别名。并且描述了一个变量存放什么类型的数据
注意:数据类型不仅帮助我们组织和操作数据,还决定了程序如何有效地利用内存。
了解数据类型的内存需求是理解计算机如何管理和操作数据的关键。
内存存储容量单位
字节(byte B):计算 存储容量的一种单位。
比特位(bit):二进制数 0 1
1个字节(byte) = 8位(bit) 二进制
1个千字节(KB) = 1024字节(byte)
1M = 1024KB
1G = 1024M
1T = 1024G
数据类型分类和计算方法
基础类型
整数类型
短整型 short / short int
整型 int
长整型 long / long int
浮点类型
单精度 float
双精度 double
字符类型 char
构造类型/自定义类型
结构体(struct)
联合体/共用体(union)
枚举(enum)
指针类型 (*/&),存储地址
空类型 void
计算某个数据类型或者变量所占的字节数
----> sizeof ( 某个数据类型或者变量名)
整型
概念
表达整数类型的数据
语法
// type var_name = 值;
int a = 123;// 定义了一个专门用来存储整数的变量a
注意
- nt 的本意是 integer,即整数的意思
- int a 代表在内存中开辟一块小区域,称为 a,用来存放整数,a 一般被称为变量。
- 变量 a 所占内存大小,在不同的系统中是不一样的,64位系统典型的大小是4个字节。
- 变量 a 有固定的大小,因此也有取值范围,典型的范围是:-2147483648到2147483647(-2^32-1到2^32-1)
整型修饰符
short:用来缩短整型变量的尺寸,减少取值范围并节省内存,称为短整型
long:用来增长整型变量的尺寸,增大取值范围并占用更多内存,称为长整型
long long:用来增长整型变量的尺寸,增大取值范围并占用更多内存,称为长长整型
unsigned:用来去除整型变量的符号位,使得整型变量只能表达非负整数
注意:使用整型修饰符后,关键字 int 可以被省略
符号位
有符号的整型数据,首位为符号位,0表示正数,1表示负数。
无符号的整形数据,没有符号位。
数据类型的值域范围
溢出:超过数据所能表达的范围,称为溢出,就像汽车里程表,最大值和最小值是相邻的
unsigned char 0 ~ 255
signed char -128 ~+127
正数: +0 +1 ....+127
负数: -0 -1 ......-127
由于 +0 和 -0 重复了, -0 表示 -128
unsigned short 0~65535(2^16-1)
unsigned int 0 ~ 4294967295(2^32-1)
eg:
(1)
unsigned char a = 255; // 0 - 255
char b = 255; // -128 ~ +127
printf("%d %u\n",a,a); // 255 255
printf("%d %u\n",b,b); // -1 4294967295
(2)
unsigned short a = -1; // 0-65535
int b = a; //65535
printf("%d\n",a);// 65535
printf("%d\n",b);// 65535
(3)
unsigned char a = -1; //0-255 a--->255
unsigned int b = -1; // 0- 4294967295
printf("%d %u\n",a,b); //a == 255 b == 4294967295
总结:
(1)当编译器以整型输出时(%d),是以补码还原的方式来解读的。
(2)当CPU对数据进行运算时,直接以内存中存放的形式进行运算,即补码的形式
(3) %u 打印的时候, 值域的范围: unsigned int 0-4294967295
(4) %hhu 打印的时候, 值域的范围: unsigned char 0-255
注意:
printf("true size:%d\n",sizeof(true)); 占 4个字节
printf("false size:%d\n",sizeof(false)); 占 4个字节
printf("false size:%d\n",sizeof(bool)); 1
总结:
1)数据类型在内存中所占的字节数跟C语言的编译系统有关
2)计算 某个数据类型 所占的字节数可以用sizeof
3) 布尔类型 要添加 #include<stdbool.h>
编码形式
计算机内部使用二进制补码来表示带符号整数。补码是为了简化计算机对整数加减法的实现而设计的一种表示方法。
原码:正数直接使用二进制来表达,最为直观的表示法,将十进制的数值转换成二进制的数值,比如a=100,在内存中是 00…001100100
反码:针对于负数的操作,原码取反(除符号位,0变成1,1变成0)
补码:负数用绝对值取反加一来表达,比如a=-3,在内存中是11…1111111101 注意负数的补码在取反加一的时候,符号位是不动的
正整数,原码,补码,反码,都是一样
char 类型
单引号只能存一个字符,即便加入多个字符,但是编译器只会存储第一个
ascii 码
概念:char数据实际上是在内存存放的是一个小于255的编号(无符号整数)用来表示字符,这个编号叫做 ASCII 码。
如何查看 ascii 码??
man ascii
注意:如果是 sizeof('a') ,那么结果就是4 ,因为在使用sizeof运算的时候,字符数据 就会转换为ascii码的形式,所以不能使用这种方法计算单个字符的大小
转义字符
概念:
所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。
而C中定义了一些字母前加 '\' 来表示常见的那些不能显示的ASCII字符,如'\0','\t','\n'等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符的意思了。
它告诉编译器需要用特殊的方式进行处理。
浮点型
概念:用来表达实数(小数)的数据类型
分类:
- 单精度浮点型(float),在64位系统中典型尺寸是4字节,精确到小数点后6位 %f
- 双精度浮点型(double),在64位系统中典型尺寸是8字节,精确到小数点后15~16位 %lf
- 长双精度浮点型(long double),典型尺寸是16字节
占用内存越多,能表达的精度越高
float f1; // 单精度
double f2; // 双精度
long double f3; // 长双精度
科学计数法:
C语言中一般浮点数有两种表示形式: 十进制形式 + 指数形式 ,两者的区别如下所示:
十进制形式:指的是数字必须以整数形式+小数形式组成,比如 10.0 、3.14 ......符合规则,以10为底数,并且科学计数法要在范围值之内。
指数形式 :一般数学上对于小数可以以10为底进行表示 比如3.14 * 10²,但是在使用英文半角输入法的时候没办法输入上底或者下底,所以C语言规定以字母e或者E来表示指数,并且要求字母e或者E的前面必须有数字,字母e或者E的后面必须为整数。
eg:
-3.14E-2 2E-3 0.3E4
printf("%e", 10000000.00);
所以:
E3 错误 因为E的前面要有数据 比如说 3.14E3
3.1e5.6 错误 因为 E的后面必须是整数
3.1e-2 对的 相当于3.1*10(-2次方)