C编译+shell+Makfile

优于内容过于繁杂,本篇持续更新~
第一次修改: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++的文件来说,建议遵循如下规则:

  1. C文件:通过gcc编译成.o文件
  2. C++文件:通过g++编译成.o文件
  3. 目标文件:在将所有的.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

commandexamplemeaning
rmrm a.cdelete a.c
rm -irm -i a.c删除前先询问一下,是否删除
rm -rrm -r testdelete folder ‘test’ and the file under it
rm -frm -f book不管文件权限,一律不再询问,执行删除
rm -rfrm -rf test删除test及其下所有的内容,无论其访问权限如何|
rmdirrmdir test失败的,只能删除空目录
rmdir -prmdir -p test与rm -rf test/ 作用相同

2.2 创建:touch/mkdir ;文件的复制:cp

commandmeaning
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的命令

commandmeaning
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文件

commodmeaning
gzip xxx压缩xxx为xxx.gz
gzip -d xxx.gz解压为xxx
gzip -r test将test文件夹下的每个文件及子文件夹中包含的文件进行压缩,但不提供打包
gzip -dr test将文件夹test及其子文件夹中的.gz文件解压

4.2 bzip2  .bz2文件

commandmeaning
bzip2 -z xxxcompress
bzip2 - d xxx.gzdecompress

4.3 tar

tar [-option] [file]

类别选项含义
主要操作-c, --createcreate a new archive -创建压缩文件
-x, --extract, --getextract files from an archive 解压缩
压缩选项-j, --bzip2filter the archive through bzip2
-z, --gzip, --gunzip, --ungzipfilter the archive through gzip
信息输出-v, --verboseverbosely list files processed 显示过程
设备选择与切换-f, --file=ARCHIVEuse 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) 命令行
commandexamplemeaning
addusersudo adduser weiwei创建用户
passwd修改密码
deluser删除用户
finger显示用户信息(需要自己安装这个命令)
addgroup添加用户组
delgroup删除用户组
group显示组内用户

6. 文件权限和所属

6.1 文件权限

(1)文件有三种权限

wrx
write 写read 读执行

(2)文件类型

d-lb
文件夹普通文件软链接块设备

(3)用户组别

(2)linux中文件权限组成
1位文件类型+9位权限,举例:
-rw-rw-r-- 1 user user 72 9月 2 20:08 a.c

-rwxrw-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

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值