嵌入式C语言学习——基于Linux与GCC(一)

Linux终端创建文件指令: https://blog.csdn.net/xtho62/article/details/118194873
vim编辑器基本指令
1.过vim编辑器打开/创建文件:vim 文件名
2.进入文件,默认在正常模式,按 i 进入编辑模式
3.在编辑模式中,按ESC退出编辑模式,返回正常模式
4.正常模式,按**:**进入命令行模式
q+回车 退出
wq+回车 保存并退出
『已解决』Linux vi/vim处于insert模式ESC无法退出且无反应

在这里插入图片描述

在这里插入图片描述

目录
1.C语言编译过程
2.C语言常见错误
3.预处理的使用
4.关键字
5.运算符

1.C语言编译过程:
预处理:去掉注释、加载头文件、替换宏定义、不进行语法检查

 cpp -o a.i 001.c(.c文件>.i文件)
 gcc -E

编译

 gcc -S(.c文件>.i文件>.s文件)

汇编

gcc -c(.c文件>.i文件>.s文件>.o文件)

链接

gcc -o(.c文件>.i文件>.s文件>.o文件>build 可执行文件)
例:gcc -o build 001.c 

linux终端执行命令

./build
在当前文件夹下执行build文件

注意:define、include不是关键字(YU)

2.C语言常见错误
一.预处理错误
1.
#include “name” 当前目录下寻找/自定义文件
#include< name > 在系统环境变量中寻找/不在当前目录中寻找

not find
abc.h: No such file or directory
#include <abc.h> 错 //自定义头文件
#include"abc.h"  对

若.h头文件与c文件不在一个文件夹而是在在当前目录的inc文件夹内:

1.#include <./inc/abc.h>
2.gcc -I./inc -o build 001.c

二.编译错误
语法错误

{ }

三.链接错误
1.原材料不够

undefined reference to ‘fun’
寻找标签是否实现了,链接时是否一起加入了链接

2.原料多了

multiple definition of ‘fun’
多次实现了标签,只保留一个标签实现。

3.怎么将两个.c文件合一链接

1.gcc -o build fun.c 001.c
or
 2.
 gcc -c -o  a.o 001.c
gcc -c -o b.o fun.c
gcc -o build a.o b.o

3.预处理的使用
1.

#include   包含头文件
#define //(替换不进行语法检查)(宏名一般大写)
  #define 宏名 宏体 // (注意加括号)
 eg:  
     #define ABC 5+3
     printf("the %d\n",ABC*5)
     #define ABC (5+3)
     printf("the %d\n",ABC*5)
#define ABC(x)  (5+(x))  //宏函数

条件预处理


#ifdef
#else
#endif
eg:
#define ABC 0 //只要定义了ifdef就通过

int main()
{
#ifdef ABC
 function();
#endif
}

预定义宏(系统定义宏)

__宏名__
__FUNCTION__ //函数名
__LINE__     //行号
__FILE__     //文件名
printf("the %s,%s,%d",__FILE__,__FUNCTION__,__LINE__)//打印当前行所在文件、函数和行号

宏展开下的#、##

#:字符串化
#include<stdio.h>
#define ABC(x) #x
int main()
{
        printf(ABC(ab123));
        return 0;
}

##:连接符号(前缀)

#include<stdio.h>
#define DAY(x) myday##x
int main()
{
        int myday1=10;
        int maday2=20;
        printf("the day is %d ",DAY(1)); //DAY(1)==myday1 
        return 0;
}

4.关键字概念

关键字一共32个
关键字是编译器预先定义了一定意义的字符串。

关键字sizeof():编译器给我们查看变量内存空间容量的工具(单位:字节)(不是函数,底层可直接调用

#include<stdio.h>
int main()
{
	int a;
	printf("the a is %lu\n",sizeof(a);
	return 0;
}

关键字return :返回值

C语言操作:资源/内存(内存类型资源,eg:lcd、led)
C语言如何描述这些资源的属性呢?资源属性之一资源的大小,并使用关键字数据类型)定义大小。

数据类型关键字:
char  1字节
int   4字节
long  4字节 OR 8字节
short  2字节 
unsignedsigned
floatdouble
void
注意:关键字代表几字节由编译器决定

char
硬件操作的最小单位 :bit(比特) 1/0
软件操作的最小单位:8bit ==1B(1字节)
网速4M ==4Mbit ==500kB
应用

  1. 通信中1次8bit char buf[ ] √ int buf[ ] ×
  2. ASCII码 8位 256个数(0-255)

int
大小由编译器决定,编译器最优的处理大小:系统一个周期所能接受的最大处理单元,int
32bit 4B int
16bit 2B int

unsigned、signed
无符号:数据(一段内存空间)
有符号:数字(加减乘除,移位时符号位不变)
区别内存空间中最高字节 是符号位还是数据位
char a = 0xff (-128)
unsigned char a =0xff (256)

float、double
float 4B
double 8B
浮点数与整数在内存中的表示形式不同
浮点型常量
1.0、1.1 (double)
1.0f (float)

void
占位标准/声明标志

自定义数据类型(还是关键字)

C编译器默认定义的内存分配不符合实际资源的形式
自定义 = 基本元素之和

struct 结构体
union 共用体
enum 枚举
typedef 定义别名

struct
元素之间的和

定义一种内存空间(下面这种写法不占用内存空间,只是定义/声明了数据类型)
eg:
struct myacbd{
	unsigned int a;
	unsigned int b;
	unsigned int c;
	unsigned int d;
}
struct myabcd mybuf;//占用了内存空间,//将 mybuf定义为myabc这样类型的内存

注意:结构体中数据之间的顺序有意义。

union 共用体

技巧性强

union共用起始地址的一段内存
/*声明一个union,不占用内存空间*/
union myabc{ 
	char a;
	int b;
}
/*使用一个union,占用内存空间*/
union myabc abc; //将abc定义为myabc这样类型的内存
unionstruct的区别
一个struct中不同数据的地址是首位相连的(这一个的首地址与上一个的尾地址相连)
一个union共用起始地址的一段内存(共用体中的前后数据可能会产生干涉)

enum 枚举
可用性低

被命名的整形常数集合
#define MON 0
#define TUE 1
#define WED 2

enum 枚举名称{常量列表};
enum week{
	Monday = 0, Tuesday = 1, Wednesday = 2,
	Thursday,Friday
}

typedef
数据类型的别名,使数据类型具有物理意义,弱化的内存大小的强调。

int a = 170;
int b = 3600;

len_t a = 170;
time_t b = 3600;

int a;  a 是一个int类型的变量
typedef int a_t; a 是一个int类型的外号
a_t mysize;mysize 的类型是int

xxx_t :代表使用了typedef

逻辑结构关键字

if else
switchcasedefault
dowhilefor
continuebreakgoto

CPU顺序执行程序
分支、选择、循环

ifelse(条件)

if(条件表达式)
	xxx;
else
   yyy;
switchcasedefault(多分支)

swtich(整型数字)      //不能是浮点数
int a;
switch(a){
	case 1;
		break;
	case 2;
}
dowhilefor
for:循环次数
(dowhile:循环条件

continuebreakgoto (循环中的控制符)
continue:继续
break:跳出
goto:只能在同一个函数中来回跳;

类型修饰符(关键字)
对内存资源属性中位置的限定

auto
register
static
const
extern
volatile
auto:默认关键字(分配的内存区域可读可写)
auto int a;
auto char b;

区域如果在{ }中,则是栈空间
register int a;
限制变量定义在寄存器上的修饰符
定义一些快速访问的变量
编译器会尽量安排CPU的寄存器去存放这个a,如果寄存器不足时,a还是放在储存器中。
关于地址:
 --内存(储存器)0x0000321
 --寄存器 R0,R2
 取地址符号&register关键字不起作用
static(静态,内存不会被自动清除,赋值后只能手动改变)
应用场景:
修饰三种数据
1.修饰函数内部变量
int fun()
{
	static int a;
}
2.修饰函数外部变量
static int a;
int fun ()
{
}
3.函数修饰符(函数名也是一个地址)
int fun(); 
static  int fun();
extern(外部声明)
const(常量定义,只读的变量,还是变量,不能直接赋值修改)

volatile
告知编译器编译方法的关键字,不优化编译
修饰变量的值的修改,不仅可以通过软件,还可以通过其他方式(硬件外部的用户)

int a =100;
while(a==100);
mylcd();
-----------------------
[a]:a的地址
f1:LDR R0,[a]
f2:CMP R0,#100
f3:JMP f1    --->优化后JMP f2
f4:mylcd();

关键字到此结束,下面是运算符¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

5.运算符

算数运算符 +-*/%
逻辑运算符||()&&()、、>>=<<=!? :
位运算
赋值运算
内存访问符号

算数运算符

   乘除(*/)
   int a = b*10; CPU可能多个周期,甚至用软件模拟的方法实现乘法
   int a = b+10; CPU一个周期就可以处理

%:取模运算
0%3=0   
1%3=1
2%3=2
3%3=0
n%m = res[0-(m-1)]
应用:
1.取一个范围内的数:
eg:给一个任意数字,得到一个1-100以内的数字?
(m%100= res
2.得到M进制的一个个位数
3.循环数据结构的下标

逻辑运算符

逻辑运算(/假,返回结果是1/0)
int a = -1;
if(a)  非零即为真
A||BB||A 不同
A&&B 同理
eg:
#include <stdio.h>
int main()
{
	int a =10;
	int  res;
	res = (a ==10 || printf("test\n"))
	printf("the res is %d\n",res);
}
结果test不会被打印
!:取非(真变假,假变真)
对比位运算取反
int a = 0x0!a  为真
~a 0xf
? : 条件运算符


Exp1 ? Exp2 : Exp3;


其中,Exp1Exp2Exp3 是表达式。请注意冒号的使用和位置。
? : 表达式的值取决于 Exp1 的计算结果。
如果 Exp1 为真,则计算 Exp2 的值,且 Exp2 的计算结果则为整个 ? : 表达式的值。
如果 Exp1 为假,则计算 Exp3 的值,且 Exp3 的计算结果则为整个 ? : 表达式的值。

(逐位)位运算

<<(左移)>>(右移) 
&()|()^(异或) 
~(取反)

移位运算符

<< 左移:是乘法 *2 ,是二进制下的移位(左移补零)
m<<1  ;m *2
m<<n  ;m *2^n
4: 0 0 1 0 0
8: 0 1 0 0 0
int a = b *32 ===> b <<5
注意区分数据和数字的区别
-1 *2 =-2
8bit
1 0 0 0 0 0 0 1  (原码)           1 0 0 0 0 0 1 0  (原码)
1 1 1 1 1 1 1 0  (反码)           1 1 1 1 1 1 0 1  (反码)
1 1 1 1 1 1 1 1  (补码)  (-11 1 1 1 1 1 1 0  (补码)  (-2
>> 右移:除以2
m>>n   m/2^n
右移补 0 or 1 与符号变量有关
int a;  a>>n 若a为负数,则符号位为1,此时右移补1
int a;  a>>n 若a为正数数,则符号位为0,此时右移补0

&、| (按位与、或)

A & 0 --> 0
&:屏蔽
	int a = 0x1234
	a & 0xff00;屏蔽低8bit,取出高8bit
A & 1 -->1
&:取出
&:清零器 CLR
eg:
清除第5位
int a;
a = a & 1 1 1 1 0 1 1 1 1 1    31     a&31  31:32bit
a = a &(0x1<<5);(避免考虑内存是32位、8位,防止对同一内存其他区域的设置误操作,并提高对不同平台的兼容性能)
a = a &(0x1<<n);清除第n位
A | 0 --->A
|:保留
A | 1 -->1
|:设置这一位为高电平的方法,设置SET
设置一个资源的bit5(6)的高电平,其他位不变
int a;
a = a|1 0 0 0 0 0;
a = (a|(0x1<<5)); ====>a|(0x1<<n) //设置第n位
eg:设置资源456bit设置为101?
a = a&(0x07<<4)
a = a|(0x05<<4) 0101
^ 按位异或
1^1 = 0 
0^0 = 0
1^0 = 1
应用:
int a =10;
int b =20;
不引入第三个变量,交换ab的值
a = a^b
b = a^b
a = a^b

结果:a=20     b=10
两个数据异或,拿异或的结果,去异或原来的某个数据,原来的两个数据相异的位相当于取反,相同的位保留。
~按位取反
~(0xf0)-->0xffff ff0f //32bitCPU 

赋值运算

=(赋值符号)
+=-=|=&=
a |(0x1<<5) 不具备自更新能力(更新不到a的内存空间中)
a |=(0x1<<5)  先与a或,结果赋值给a

内存访问符号

()、[ ]{ }->.&*
()
1.限制符 (a+b)*c
2.函数访问 int fun();
			  fun(); 
[ ]  
数组
内存访问的ID符号
a[1]、a[2]
{ }
1.函数体的限制符
2.struct abc{xxx}
->/.
自定义空间中不同成员变量的访问方法
-> :地址访问
.  :变量访问
&*
&p :取p的地址
a&b:a和b做与运算

*p:名字为p的指针
*10:乘以10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值