LINUEX部分指令 C语言

本文详细介绍了Linux系统中使用gcc编译器进行C语言编程的相关指令,包括预处理、编译过程以及gcc的各种选项。还讨论了C语言的预处理指令,如#include和条件编译,并讲解了自定义数据类型如struct、union和enum。同时,文章涵盖了指针、运算符、数组、逻辑结构、类型修饰符和内存管理等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

./ 文件名 表示在当前目录执行某文件
linux系统中0代表成功,非0代表失败

gcc编译器

gcc是一种翻译器,将高级语言翻译成机器指令(翻译组织)
创建文件使用gcc指令时要加后缀.c就表示为c语言

gcc -o =output输出
gcc -o 输出文件名 输入文件名
输出文件为一个新建文件 输入文件为一个待翻译或执行的文件
即将c输出成机器指令
gcc -v 打印信息
显示调用的组织
需要调用多步
gcc-S 后跟- o 大写的S 将.c文件先翻译成.s(汇编)
gcc -c 将.s文件变成.o (目标文件)
gcc-o 将.o变为可执行文件
事实直接用gcc -o就自动执行前几步命令

gcc -E 显示预处理文件 (.i为预处理文件)

C的预处理

#include <>(尖括号一般从系统的环境变量种中寻找)“”(双引号一般是自己定义 的)尖括号的从文件只从系统库中找,双引号的是先从系统中找再从当前目录寻找文件
gcc -I跟查找头文件的目录 用来解决预处理中not find 错误

条件编译 #ifdef #else #endif

比如在工程开发调试时需要使用_FILE_来看所在文件名,但是发行版本又不能带有
如下代码。如果在预处理中定义了ABC则显示文件名,否则不显示

#include<stdio.h>
int main()
{
#ifdef ABC
printf("===%s===",_FILE_);
#endif
printf("hello world!");
return 0;
}

gcc-D等价于在编译之前加入宏定义
如 gcc-DABC=#define ABC
预定义宏(系统预定义,由下划线组成)
FUNCTION 函数名
LINE 行号
FILE 文件名
显示当时执行这条语句所在的函数名,第几行和所在文件名

宏展开下的#、##使用
# 字符串化 如defineABC(x) #x
#include <stdio. h>
int main()
{
printf(ABC(ab)); // ABC(ab)等效于 “ab”
return 0;
}

##连接符 连接前后两个字符串

#define DAY(x) myday##x
{
int myday1=10;
int myday2=20;
}
其中DAY(1)=myday1=10

硬件操作以BIT为单位,软件中最小操作单位为byte

系统一个周期,所能接受的最大处理单位:int

32bit 4B int
16bit 2B int

=========================
char 1字节所能表示最大255
可以在数字后加L或l代表long类型
如:char a=300l;

自定义数据类型

struct
结构体,里面的数据地址一个接一个
union
所有数据共用一个地址
enum
枚举类型,相当于一个宏定义的集合
例如星期
enum week
{
MON=1;THU=2;WEN=3…
}
typedef
数据类型的别名
增加程序可读性
如:
typedef int time_t
time_t a;就等价于 int a;
可以容易看出a是与时间相关变量
一般typedef定义的别名都加_t来区分

逻辑 结构

goto语句 goto在同一函数内跳转,不可再不同函数

类型修饰符

对内存资源存放位置的限定

auto 自动变量,在普通内存中可读可写的区域,如果{auto char a};区域在大括号内则表示a 在栈空间内(默认是auto类型)

register 限制变量放在寄存器中(编译器会尽量安排CPU寄存器存放a变量,如果寄存器不足时,a还是放在存储器中)取地址符号对在寄存器中的变量无效

static
应用场景:
修饰3种数据:
1)函数内部变量
2)函数外部变量(全局变量)
3)函数

extern外部声明

const:
常量;定义出来的变量不可改变
C中可以用指针修改
如;const int a =0x200;
int b = 0x300;
int *p=&b;
p【1】=100; 因为C中是从高地址到低地址存放数据,所以b的地址加1为a的地址
就改变了A的值

volatile
告知编译器编译方法的关键字,编译器不优化编译
例如
int a=100;
while(a==100);
func();
翻译成汇编为
f1: LDR R0, [a] [a]为a的地址
f2: CMP R0 , #100
f3: JMP f1
f4 func()

编译器会自动进行优化,把f3变成JMPf2 这样可以节省时间不跟外部存储打交道,但是如果a是由外部设备决定的这样程序就没法得到a 的值导致程序出错,此时使用volatile可以取消优化(在int a 之前加)

运算符

1.算数运算符
+、-、*、/、% 加减CPU可以一个周期处理,乘除可能多个周期、甚至利用软件的模拟方法去实现。有些CPU性能不支持乘除,所以能不用可以不用
求模%
0%3=0 1%3=1.。。2%3=2 。3%3=0。4%3=1。(012循环可以得到一个循环的下标)
所以n%m+【0,m-1】会得到这个区间的数
可以用来取一个范围的数‘
例如:给一个任意数字,得到一个1到100以内的数字
(m%100)+1便可得到1-100以内的数字
2.逻辑运算符
真 假 0为假 非0为真 A||B与B||A不一样,因为会先判断,若A为真就不判断B了 A&&B同理,A为假便不判断B
!为非,若a=0x0 !a为真 ~a为按位取反即a=0xffff
?: a+b ? c:d
3.位运算
<<左移 >>右移(二进制下移位) 左移相当于乘2
-1 -2
原码 1000 0001 1000 0010
反码 1111 1110 1111 1101 符号位不变,其他取反
补码 1111 1111 1111 1110

右移
与 符号变量有关

int a a>>n 如果是有符号数右移时左边第一位还是符号位
unsigned int a a>>n

int a=XXX
while(a){
a>>1;
}
若a为负数则while不会结束符号位始终为0
&屏蔽,取出。清零器
int a=0x1234
a&0xff00 屏蔽第八位,取出高八位

||
置位,设置为高电平
设置一个资源的bit5为高电平,其他位不变
int a;
a=(a||(0x1<<5))
清楚第五位
a=(a&(~(0x1<<5))) 取反
用移位安全不会影响别的位,且移植性好。如果用十进制比如用32 。则会影响前面高位

异或^

相同为假不同为真

a=a^b;
b=a^b
a=a^b
例a=4
b=2

则a=100

b=010
a=a^b110
b=a^b
100
a=a^b==010
可完成ab值互换

取反~
逐位取反
如0xf0 取反应该也是一个32位的数字 位0xffff ff0f

4.赋值运算
+=
a+=b a=a+b
||=和&&=也一样

5.内存访问符号
()函数访问符号
[]内存访问的ID号如数组a[1]a[2]
{}函数体的限制符号
对于连续自定义空间不同成员变量的访问方法
-> 地址访问
. 变量访问

&取地址
*指针

指针

23位系统中,指针位4字节
大小端模式。高位高址 高位低址

指针+修饰符
const
常量,只读
const char *p
char const *p
以上两种相同char指p是一个字节,const表示只读,建议使用第一种
意义是p指向的地址可以变,但是指向的地址(内容)是只读的不可以改变 比如指向字符串,“”内的不修改
char *const p
char *p const
相同 建议第一种
指向的位置不可变,但指向位置里的信息可变。一般出现这个都是指向硬件资源 如显卡, 显卡缓存的地址是固定的,

const char *const p 指向的地址与地址里的内容都不能变,一般工程中产生ROM

volatile
一般是操作硬件时,防止优化指向内存地址

typedef
增加程序可读性

typedef char* name_t

name_t a;等价于 char* a;

指针+运算符
int p;设p地址为 【0x12】
p+1 为【0x12+1
(sizeof(*p))】
指针的加法使劲上是加一个单位,单位的大小可以使用sizeof(*p)

【】
ID,标签
指针内容标签访问方式
p+n=p【n】
这种访问方式直接访问内容

指针的逻辑操作符

== != 0X0:地址的无效值,结束标志

数组

指针变量的特殊化
内存分配的一种形式
数组名是一个常量不能放到等号左边

数组空间的初始化

空间定义时,就告知编译器的初始化情况,空间的第一次赋值,初始化操作
a[10]={20,30,40};大括号内是一个空间
但是C不支持空间到空间的拷贝
数组空间的初始化与变量的初始化本质不同,尤其在嵌入式的裸机开发中,空间的初始化往往需要库函数的辅助

只能第一次初始化,后面需要修改内存空间需要逐一处理

当一块空间被当成字符空间,提供一套字符拷贝函数
字符拷贝原则:
内存空间和内存空间的逐一赋值功能的一个封装体
一旦空间中出现了\0,那么函数结束
shrcpy
因为碰到\0才会停止,容易造成内存泄漏,工程中一般不使用
strncpy
限制了拷贝个数,只能拷贝目的空间大小的数据
strncpy(src,dest,n)
n为字节数
以上一定不要用于数据采集,因为字符串拷贝函数看到0就会停止

非字符串空间
数据采集(如采集温度)采集的最小单位为0x00—0xff(8比特为最小单位)
(字符空间指可以用ASCLL码解码的空间,给人看的)
char buf【10】—>string(字符)
unsigned char【10】—>data(数据)
拷贝三要素’1、src(source)2.dest(目的地)3.个数

memcpy()
例int buf【10】
int sensor_buf【10】
memcpy(buf,sensor_buf【10】,10*sizeof(int))
memcpy函数中的传递个数单位是字节

多维数组
inta 【2】【3】
int (*p)【3】
不加括号会被当成数组处理
加了括号说明一个指针,一次指向3个INT类型(指向一行)

结构体字节对齐

#include<stdio.h>
struct abc
{
char a;
int b;
};
int main()
{
struct abc buf;
printf("%lu".sizeof(buf));
}

最后得到的空间为8个字节(char1字节,int4字节,为什么不是5字节呢?)
效率问题,牺牲一点空间,换取时间的效率
比如32位CPU如果要取一个数,取四个字节会把数据总线占满达到最高效率,
但是指针存在自更新,会自动更新到四字节后,所以结构体的字节对齐,会空3个字节给char a
结构体的大小一定是4的倍数,结构体成员顺序不一样也会影响大小

#include<stdio.h>
struct abc
{
char a;
short c;
int b;
};
struct ab
{
char a;
int b;
short c;
};
int main()
{
struct abc buf;
struct ab buf1;
printf("%lu:%lu",sizeof(buf),sizeof(buf1));
}

上述结果buf为8个字节,buf1为12个字节

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值