优于内容过于繁杂,本篇持续更新~
第一次修改:2023/12/24
第二次修改:2023/12/27 新增C与C++混合编程案例,详见1.2小节
第一章 C编译
1. C语言编译过程
四个步骤:preprocessing–>compilation–>assemble–>linking
即:预处理–>编译–>汇编–>链接
步骤 | 功用 |
---|---|
预处理 | 将所有的#include头文件替换为头文件里面的内容,以及将#define的宏定义进行替换,文件仍是.c文件,只是代码的体积增大 |
编译 | 将预处理后的文件转换为特定的汇编代码(assembly code),即.s文件,是汇编语言 |
汇编 | 将汇编代码转换成机器码(machine code), 生成二进制文件.o,又称为目标文件 |
链接 | 将多个目标文件和所需要的库稳健链接成最终的可执行文件(executable file).out文件 |
1.2 C与C++混合编程
1.2.1 基本用法
extern "C"
#ifdef __cplusplus
extern "C"
{
#endif
// C代码的内容
#ifdef __cplusplus
}
#endif
在混合编程中,必须注意一点,需要保证某部分代码按照C的方式编译时,必须将内容通过上述格式框起来。
1.2.2 C++代码中调用C代码
直接调用,基本不会出问题。C++兼容C。
1.2.3 C中调用C++
因为C++中有封装、多态、模板(STL)等概念,而C没有。因此,C++必须为C函数调用提供一系列接口函数。
(1)案例:C中调用C++类
C++提供一个Animal类,该类有一个成员变量age,3个成员函数。我们的目标是:从C代码中访问该类,并设置该成员变量或调用成员函数。
C++代码中提供对C的支持如下:
//cxx_code.h
#ifndef CXX_CONDE_H_
#define CXX_CONDE_H_
#ifdef __cplusplus
extern "C"{
#endif
enum ops{
Hello,
EchoAge,
SetAge,
};
extern void * animal_ptr;//外界函数调用
extern void cxx_code_init();
extern void cxx_code_exit();
extern void callclass(enum ops type,void * ptr,...);
#ifdef __cplusplus
}
#endif
#endif
//cxx_code.cpp
#include "cxx_code.h"
#include <iostream>
#include <stdarg.h>
using namespace std;
class Animal
{
public:
Animal(int age){
mAge = age;
};
~Animal(){};
virtual void sayHello(void){
cout << "Animal hello" << endl;
};
void setAge(int age){
mAge = age;
};
virtual void sayAge(void){
cout << "age="<<mAge<< endl;
};
int mAge;
};
void * animal_ptr;
void cxx_code_init(){
class Animal *p = new Animal(1);
animal_ptr = p;
}
void cxx_code_exit(){
class Animal *p = (class Animal *)animal_ptr;
delete p;
animal_ptr = nullptr;
}
void callclass(enum ops type,void * ptr,...){
class Animal *p = (class Animal *)ptr;
switch (type)
{
case Hello:
p->sayHello();
break;
case EchoAge:
p->sayAge();
break;
case SetAge:
va_list args;
va_start(args,ptr);
int newAge;
newAge = va_arg(args,int);
va_end(args);
p->setAge(newAge);
break;
default:
break;
}
}
C代码中通过如下操作调用
//C代码
#include "cxx_code.h"
int main(){
cxx_code_init();//创建c++类
callclass(Hello, animal_ptr);//say hello
callclass(EchoAge, animal_ptr);//以前的年龄
callclass(SetAge, animal_ptr, 5);//重新设置年龄
callclass(EchoAge, animal_ptr);//新的年龄
cxx_code_exit();//摧毁c++类
return 0;
}
如何编译链接该工程文件,见下一小节
1.2.2 如何编译链接C和C++代码
一个工程文件通常包含多项文件,对于既有C、又有C++的文件来说,建议遵循如下规则:
- C文件:通过gcc编译成.o文件
- C++文件:通过g++编译成.o文件
- 目标文件:在将所有的.o文件链接成目标文件时,采用g++编译器(不建议直接采用ld)
(1)案例
仍然是上一小节的代码,其Makefile文件参考如下:
# target
target := main
# compiler
cross_compile :=
cc := $(cross_compile)gcc
cxx := $(cross_compile)g++
# include path
current_path :=$(shell pwd)
include_path = -I$(current_path)
# compile flag
ccflags = $(include_path)
cxxflags = -std=c++11 -Wall $(include_path)
# source file
obj_cxx := $(patsubst %.cpp, %.o, $(wildcard *.cpp))
obj_c := $(patsubst %.c, %.o, $(wildcard *.c))
obj_all := $(obj_c) $(obj_cxx)
# export to son Makefile
export eigen_path cross_compile cc cxx
# all
all:$(target)
$(target):$(obj_all)
$(cxx) $(cxxflags) -g -o $@ $^
%.o:%.c
$(cc) $(ccflags) -c -g $< -o $@
%.o:%.cpp
$(cxx) $(cxxflags) -c -g $< -o $@
# clean
clean:
rm -f $(target) *.o
编译成功后,运行结果如下:
在这里插入图片描述
注意,图中的警告不会影响正常运行,因为类创建后没有再请求其他内容,不会内存泄露。
1.3 gcc选项及命令
CFLAGS命令 | 含义 |
---|---|
-g | 在编译过程中产生所有的调试信息 |
-Wall | 在编译阶段显示所有错误 |
-Werror | 将警告当做错误处理,从而出现警告是便会停止编译 |
-Ox | 编译器的优化级别 |
-Ox | 含义 |
---|---|
-O0 | 编译过程无优化 |
-O1 | 编译过程使用默认优化 |
-O2 | 使用二级优化 |
-O3 | 使用最高级优化 |
-Os | 相当于-O2.5优化,但又不所见代码尺寸 |
第二章 shell
1.入门
1.1 #与$用户的区别
#:root权限用户,拥有最高权限,安装软件时不需要输入密码
$: 普通用户,每次对系统进行更改时都需要输出密码
链接: 用户级别切换或创建.
user@userDeivce:~$
变量 | 含义 |
---|---|
user | 当前用户 |
userDeivce | 主机名 |
~ | 当前用户(该部分显示的实际上是当前目录) |
$ | 普通用户 |
# | root用户 |
1.2 Ubuntu下颜色区分文件
亮蓝色: 软连接文件
绿色:实体,可执行文件
1.3 man
查看命令的用法
帮助命令
1.4 echo命令
1.输出字符串 echo [字符串]
2.提取变量的值? echo [$变量]
user@userDeivce:~$ echo SHELL
SHELL
user@userDeivce:~$ echo $SHELL
/bin/bash
1.5 date命令
设置或显示 系统的时间日期
2.文件与文件夹的创建、删除、移动、复制、重命名
假设test目录结构如下
test
├── a.c
├── b.c
└── question
└── sf.c
2.1 删除:rm /rmdir
command | example | meaning |
---|---|---|
rm | rm a.c | delete a.c |
rm -i | rm -i a.c | 删除前先询问一下,是否删除 |
rm -r | rm -r test | delete folder ‘test’ and the file under it |
rm -f | rm -f book | 不管文件权限,一律不再询问,执行删除 |
rm -rf | rm -rf test | 删除test及其下所有的内容,无论其访问权限如何| |
rmdir | rmdir test | 失败的,只能删除空目录 |
rmdir -p | rmdir -p test | 与rm -rf test/ 作用相同 |
2.2 创建:touch/mkdir ;文件的复制:cp
command | meaning |
---|---|
touch a.c | 在当前路径下创建文件a.c |
mkdir test | 在当前目录下创建文件夹test |
mkdir -p test/question/se | 创建多级目录 |
cp a.c b.c | 将文件a.c复制,并另存为b.c |
2.3 mv 移动/重命名
linux系统中没有rename的命令
command | meaning |
---|---|
mv a.c b.c | 其运行结果是将当前的文件重命名为b.c |
mv test/ test1/ | 将文件夹test重命名为test1,该文件夹下的内容不变 |
mv test1/a.c book/ | 将test1中的文件a.c移动到book目录下,在执行命令后,test1中就没有a.c的文件了 |
mv test1/a.c book/asf.c | 将文件a.c移动至book目录下,并重命名为asf.c |
2.4 rename 重命名
可能需要安装
带模式匹配的重命名方式如下:
假设我有文件test_1.txt test_2.txt … test_100.txt
现在需将所有文件名称更改为test_ok_1.txt …的模式,则可以通过如下方式进行:
rename "s/test_/test_ok_/" ./*.txt
符号 | 含义 |
---|---|
rename | 命令 |
“s/test_/test_ok_/” | test_表示要替换的原内容,test_ok_表示要替换成分字符 |
./*.txt | 当前路径下所有的txt文件 |
3.软件安装
3.1 apt-get
使用apt安装软件需要root权限,因此一般需要加上sudo,具体命令如下:
sudo apt-get install -['name']
其中,-['name']
是需要安装库文件或软件名称
3.2 dpkg
通过在网络上下载.deb文件(类似与windows下的.exe文件),通过命令:
sudo dpkg -i xxx.deb
4.文件的压缩和解压
4.1 gzip .gz文件
commod | meaning |
---|---|
gzip xxx | 压缩xxx为xxx.gz |
gzip -d xxx.gz | 解压为xxx |
gzip -r test | 将test文件夹下的每个文件及子文件夹中包含的文件进行压缩,但不提供打包 |
gzip -dr test | 将文件夹test及其子文件夹中的.gz文件解压 |
4.2 bzip2 .bz2文件
command | meaning |
---|---|
bzip2 -z xxx | compress |
bzip2 - d xxx.gz | decompress |
4.3 tar
tar [-option] [file]
类别 | 选项 | 含义 |
---|---|---|
主要操作 | -c, --create | create a new archive -创建压缩文件 |
-x, --extract, --get | extract files from an archive 解压缩 | |
压缩选项 | -j, --bzip2 | filter the archive through bzip2 |
-z, --gzip, --gunzip, --ungzip | filter the archive through gzip | |
信息输出 | -v, --verbose | verbosely list files processed 显示过程 |
设备选择与切换 | -f, --file=ARCHIVE | use archive file or device ARCHIVE |
5. 用户
5.1 用户类型:
1.初次创建时的用户
2.root用户
3.普通用户
用户记录在: /etc/passwd
用户密码存放在: /etc/shadow
5.2 用户和用户组
每个用户都有一个ID ---- UID
user:x:1000:1000:user,,,:/home/user:/bin/bash
第一个1000是用户ID,即UID;
第二个1000是用户组ID,即GID;
同一个用户组的用户可以访问这个用户组的公共文件(即控制文件访问权限)
用户组记录: /etc/group
一个用户可以加入多个用户组
5.3 用户和用户组的创建
(1) 图形化界面:gnome-system-tools
(2) 命令行
command | example | meaning |
---|---|---|
adduser | sudo adduser weiwei | 创建用户 |
passwd | 修改密码 | |
deluser | 删除用户 | |
finger | 显示用户信息(需要自己安装这个命令) | |
addgroup | 添加用户组 | |
delgroup | 删除用户组 | |
group | 显示组内用户 |
6. 文件权限和所属
6.1 文件权限
(1)文件有三种权限
w | r | x |
---|---|---|
write 写 | read 读 | 执行 |
(2)文件类型
d | - | l | b |
---|---|---|---|
文件夹 | 普通文件 | 软链接 | 块设备 |
(3)用户组别
(2)linux中文件权限组成
1位文件类型+9位权限,举例:
-rw-rw-r-- 1 user user 72 9月 2 20:08 a.c
- | rwx | rw- | r– |
---|---|---|---|
文件类型 | 用户权限 | 用户组内的成员 | 其他用户权限 |
普通文件 | 读\写\执行 | 读\写 | 读 |
6.2 修改权限
chmod:修改文件权限
chown:修改文件所属用户
-R对所有文件进行更改
7.文件链接
符号连接(软连接):类似于快捷方式
硬连接:通过Inode连接产生新的文件名.Inode相当于文件ID,查找文件时先找Inode,再才能读出文件内容
7.1 ln命令
-s, --symbolic make symbolic links instead of hard links 创建软连接
-f, --force remove existing destination files 强制创建连接文件,如果目标存在,那么先删除目标文件,再建立连接文件
命令 | 含义 |
---|---|
ln | 硬连接 |
ln -s | 软连接 |
7.2 硬链接
多个文件都指向同一个inode
1)多个具有相同node的文件互为硬连接文件,创建硬连接相当于文件实体多了入口
2)只有删除了源文件和所有的硬连接文件,文件实体才会被删除
3)修改仍和一个文件,所有的文件都会更改
4)不能跨文件系统(如从电脑硬盘连接到一个移动U盘)
创建方式 ln hello hello1
hello :源文件
hello1: 硬连接位hello1文件
7.3 符号连接(相当于快捷方式)
1)源文件删除后,就被删除了
2)可以连接到目录
3)必须使用绝对路径
5)指示文件时通过->来指示具体的连接文件
8.文件打开及编辑
8.1 vi/vim
Ubuntu自带一个vi编译器
vi xxx
vim xxx
8.2 sed
sed又称为流编辑器(stream editor)。
8.3 awk/gawk
8.3 cat/more/less
第三章 Makefile
1. 符号
符号 | 含义 |
---|---|
* | 通配符 |
$ | 变量 |
参考资料:
[1] 《Unix系统编程》
[2] 跟我一起makefile