GCC/CLANG编译器

2023-10-29

GCC是在linux下使用的编译器,Clang是在mac上使用的编译器,两者的命令几乎一样.

对于苹果iOS,使用的编译器是LLVM,相比于xcode 5版本前使用的GCC编译速度提高了3倍。

LLVM是编译器工具链技术的一个集合,其中的lld项目,就是内置链接器。LLVM架构前段为Clang后端为LLVM

在这里插入图片描述
整体的编译器架构就是 LLVM 架构;Clang 大致可以对应到编译器的前端,主要处理一些和具体机器无关的针对语言的分析操作;编译器的优化器和后端部分就是之前提到的 LLVM 后端,即狭义的 LLVM

本文运行环境为mac


编译指令

gcc/clang -g -O2 -o test test.c -I... -L... -l...

-g 输出文件中的调试信息
-O 大写的O,对输出文件做指令优化,2表示对文件进行第二个级别的编译优化,更彻底,如果调试的话,则不需要-O
-o 输出文件
-I指定头文件位置,使用第三方库或者自己创建,
-L 指定lib库位置
-l 意为link,指定使用哪个库,不一定所有都用


编译过程

vim main.c
创建一个main函数文件,c程序必须以main函数为入口点

# include <stdio.h>
 
int main()
{
    printf("hello world\n");
    return 0;
}

预处理

gcc -E main.c -o main.i

-E 表示生成预处理文件

具体内容:

  1. 宏定义指令 #define xxxx
  2. 条件编译 #if #else #endif...
  3. 头文件包含指令 #include 将头文件和源代码拷贝到一起
  4. 特殊符号处理 例如对方法参数中的空格处理

常见问题
不能在头文件中定义全局变量,因为在头文件中定义全局变量将会使所有包含该头文件的文件存在该段代码,也就是说这些文件将定义一个相同的全局变量,这样将不可避免的造成冲突

首先对源文件进行预处理,这个过程主要是处理一些#号定义的命令或语句(如宏、#include、预编译指令#ifdef等),生成*.i文件。即绑定头文件和宏判定等操作,将头文件和源代码拷贝到一起,以便编译器进行编译

生成汇编代码

gcc -S main.i -o main.s

-S 让编译程序在生成汇编语言输出

具体内容
编译环节是指对源代码进行语法分析,并优化产生对应的汇编代码的过程,通过词法分析语法分析,将其翻译成等价的中间代码或汇编代码。局部优化、控制流分析和循环优化、数据流的分析和全局优化。

进行词法分析、语法分析和语义分析等,生成*.s的汇编文件

词法分析

编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”(引用自《C Traps and Pitfalls》)。
词法分析器读入组成源程序的字符流,并且将他们组织成为有意义的词素(lexeme)序列。对于每个词素,词法分析器产生词法单元token(符号)作为输出(引用自《编译原理》)。
token指的是程序的一个基本组成单元—词法单元。token的作用相当于一个句子中的单词,从某种意义上来说,一个单词无论出现在哪个句子中,它代表的意思都是一样的,是一个表义的基本单元。与此类似,token就是程序中的一个基本信息单元。词法分析器将源文件的字符流转换为token的过程被称作词法分析(lexical anaysis)

对某一个源文件进行词法分析,可以使用下面这个命令

clang -fmodules -E -Xclang -dump-tokens main.m
annot_module_include '# include <s'		Loc=<main.m:1:1>
int 'int'	 [StartOfLine]	Loc=<main.m:3:1>
identifier 'main'	 [LeadingSpace]	Loc=<main.m:3:5>
l_paren '('		Loc=<main.m:3:9>
r_paren ')'		Loc=<main.m:3:10>
l_brace '{'	 [StartOfLine]	Loc=<main.m:4:1>
identifier 'printf'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:5:5>
l_paren '('		Loc=<main.m:5:11>
string_literal '"hello world\n"'		Loc=<main.m:5:12>
r_paren ')'		Loc=<main.m:5:27>
semi ';'		Loc=<main.m:5:28>
return 'return'	 [StartOfLine] [LeadingSpace]	Loc=<main.m:6:5>
numeric_constant '0'	 [LeadingSpace]	Loc=<main.m:6:12>
semi ';'		Loc=<main.m:6:13>
r_brace '}'	 [StartOfLine]	Loc=<main.m:7:1>
eof ''		Loc=<main.m:7:2>

int 'int' [StartOfLine] Loc=<main.m:3:1> 就是一个token,每个token后面的Loc代表这个token在源文件中的位置。例如Loc=<main.m:4:1>代表这个token位于main.m文件中的第4行第1个位置。

注意:这里的位置是从1开始,而非0

ps:注释虽然没有真实的意义,但是注释占用的行依旧是有效的,在词法分析阶段并没有被忽略掉。这样的好处是,词法分析后的tokenLoc就是真实的Location

当然,和预处理一样,如果源文件中有import其他文件,那么还需要使用-isysroot参数来指定iPhoneSimulator.sdk的路径,如下:

clang -fmodules -E -Xclang -dump-tokens -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m

语法分析

将词法分析的token解析处理成抽象语法树AST(abstract syntax tree)的过程称作语法分析(semantic analysis)。即语法分析的输入是token,输出是ASTAST则更加直观的反映了代码的内部结构和逻辑。使用clang -fmodules -fsyntax-only -Xclang -ast-dump main.m可以对源文件进行语法分析。

TranslationUnitDecl 0x7f85fb828ce8 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7f85fb829260 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7f85fb828f80 '__int128'
|-TypedefDecl 0x7f85fb8292d0 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7f85fb828fa0 'unsigned __int128'
|-TypedefDecl 0x7f85fb829370 <<invalid sloc>> <invalid sloc> implicit SEL 'SEL *'
| `-PointerType 0x7f85fb829330 'SEL *'
|   `-BuiltinType 0x7f85fb8291c0 'SEL'
|-TypedefDecl 0x7f85fb829458 <<invalid sloc>> <invalid sloc> implicit id 'id'
| `-ObjCObjectPointerType 0x7f85fb829400 'id'
|   `-ObjCObjectType 0x7f85fb8293d0 'id'
|-TypedefDecl 0x7f85fb829538 <<invalid sloc>> <invalid sloc> implicit Class 'Class'
| `-ObjCObjectPointerType 0x7f85fb8294e0 'Class'
|   `-ObjCObjectType 0x7f85fb8294b0 'Class'
|-ObjCInterfaceDecl 0x7f85fb829590 <<invalid sloc>> <invalid sloc> implicit Protocol
|-TypedefDecl 0x7f85fb8298f8 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7f85fb829700 'struct __NSConstantString_tag'
|   `-Record 0x7f85fb829660 '__NSConstantString_tag'
|-TypedefDecl 0x7f85fb829990 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7f85fb829950 'char *'
|   `-BuiltinType 0x7f85fb828d80 'char'
|-TypedefDecl 0x7f85fb861888 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7f85fb861830 'struct __va_list_tag [1]' 1 
|   `-RecordType 0x7f85fb8616a0 'struct __va_list_tag'
|     `-Record 0x7f85fb861600 '__va_list_tag'
|-ImportDecl 0x7f85fb862100 <main.m:1:1> col:1 implicit Darwin.C.stdio
|-FunctionDecl 0x7f85fb862190 <line:3:1, line:7:1> line:3:5 main 'int ()'
| `-CompoundStmt 0x7f85fb9f77e8 <line:4:1, line:7:1>
|   |-CallExpr 0x7f85fb9f7750 <line:5:5, col:27> 'int'
|   | |-ImplicitCastExpr 0x7f85fb9f7738 <col:5> 'int (*)(const char *, ...)' <FunctionToPointerDecay>
|   | | `-DeclRefExpr 0x7f85fb9f7678 <col:5> 'int (const char *, ...)' Function 0x7f85fb862290 'printf' 'int (const char *, ...)'
|   | `-ImplicitCastExpr 0x7f85fb9f7798 <col:12> 'const char *' <BitCast>
|   |   `-ImplicitCastExpr 0x7f85fb9f7780 <col:12> 'char *' <ArrayToPointerDecay>
|   |     `-StringLiteral 0x7f85fb9f76d8 <col:12> 'char [13]' lvalue "hello world\n"
|   `-ReturnStmt 0x7f85fb9f77d0 <line:6:5, col:12>
|     `-IntegerLiteral 0x7f85fb9f77b0 <col:12> 'int' 0
`-<undeserialized declarations>

有了抽象语法树,clang就可以对这个树进行分析,找出代码中的错误,很多编译期的检查都是针对于抽象语法树的检查。比如类型不匹配未实现对应的方法

链接:https://www.jianshu.com/p/94c2a7a311d4

语义分析

使用语法分析产生的语法树(AST)符号表检查源程序是否和语言定义的语义一致的过程被称为语义分析。这个定义听起来比较绕,后面会解释。

语义分析的过程同时也收集类型信息,并把类型信息存储在语法树(AST)符号表中,以便随后的中间代码生成过程中使用。

语义分析一个重要的部分就是“类型检查”“自动类型转换”。编译器检查每个运算符是否有匹配的运算分量。所谓运算分量就是指被运算符操作的。拿C语言的语义分析举例,比如a + b, 其中“+”就是运算符,a和b就是这个运算符的分量。如果a和b都是整型或浮点型,这说明“+”运算符具有匹配的运算分量。如果a或b其中一个是字符串类型,则说明“+”运算符不具备匹配的运算分量。又比如,很多语言中要求数组的下标是一个非负整数,如果浮点数作为下标,编译器就必须报告错误。

生成中间代码

在把源程序翻译成目标代码的过程中,一个编译器可能构造出一个或多个中间表示(Intermediate Representation或IR)。这些中间表示可以有多种形式。语法树(AST)就是一种中间表示形式。–摘抄自《编译原理》

我们已经知道,语法分析生成AST语义分析会对根据AST和符号表对源程序进行检查。那么语法分析语义分析都完成后,clang会遍历AST生成一种明确的、低级的或类机器语言的中间表示IRLLVM IRLLVM套件里面的中间表示(LLVM Intermediate Representation)LLVM IR也是前端(clang)的输出,后端的输入。

LLVM IR有3种表示形式,分别是:

text格式:便于阅读的文本格式,类似于汇编语言,拓展名.llxcrun clang -S -emit-llvm main.c -o main.ll
memory格式:内存格式
bitcode格式:二进制格式,拓展名.bc$ clang -c -emit-llvm main.m

ps:以上三种形式的本质是等价的,就好比水可以有气体、液体、固体3种形态。

我们使用clang -S -emit-llvm main.m命令来获取text格式的文件,文件后缀名是.ll,使用文本编辑器即可打开,如下:

; ModuleID = 'main.m'
source_filename = "main.m"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.13.0"

@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00", align 1

; Function Attrs: noinline optnone ssp uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { noinline optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
!llvm.ident = !{!7}

!0 = !{i32 1, !"Objective-C Version", i32 2}
!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 7, !"PIC Level", i32 2}
!7 = !{!"Apple LLVM version 10.0.0 (clang-1000.11.45.5)"}

Clang还会收集源程序的信息,并把信息存放在符号表(symbol table)中。符号表LLVM IR会被传递给后端。


代码生成

代码生成(CodeGen)代码生成器完成。以源程序的中间表示(IR)作为输入,并把它映射到目标语言。如果目标语言是机器代码,那么就必须为程序使用的每个变量选择寄存器或内存位置。然后中间指令(IR)被翻译成为能够完成相同任务的机器指令序列(二进制文件)。代码生成的一个至关重要的方面是合力分配寄存器存放变量的值

LLVM IR

有些编译器的结构单纯的分为前端后端,比如GCC。而LLVM的结构并不是单纯的分为前端和后端LLVM编译器集合是围绕着一组精心设计的中间表示形式而创建的,这些中间表示形式使得我们可以把特定语言前端特定目标机后端相结合。使用这些集合,我们可以把不同的前端某个目标机的后端结合起来,为不同的源语言建立该目标机上的编译器。类似的,我们可以把一个前端不同的目标机后端结合,针对不同目标机的编译器。

这样说可能比较绕,本质上是LLVM IR优化器会做一些与代码无关的优化,所以如果LLVM将来需要支持一门新的编程语言,只需针对这个编程语言提供一个新的前端。如果将来LLVM需要支持一款新的机器架构,只需要针对这款机器架构提供一个新的后端。而LLVM IR优化器是通用的。这样一来LLVM就变得易扩展

个人理解大概是这个意思:

编译过程从左至右

前端(C/C++) - LLVM - 后端(新架构)
前端(新语言) - LLVM - 后端(x86_64)

汇编

汇编器以汇编代码作为输入,将汇编代码转换为机器代码,最后输出目标文件(object file)。

gcc -c main.s -o main.o

-c 表示编译、汇编指定的源文件(也就是编译源文件),但是不进行链接

将对应的汇编指令翻译成机器指令,生成可重定位的二进制目标文件.o


链接

链接器把编译产生的.o文件(dylib,a,tbd)文件,生成一个mach-o(可执行文件)文件。

xcrun clang main.o -o main

使用nm命令,查看可执行文件的符号表

nm -nm main

lib库的链接

vi add.c 创建一个add方法文件

#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
int add(int a, int b){
return (a+b);
}
#endif 

然后编译,并使用libtool,生成一个静态库包含add.o

gensees-iMac:study gensee$ vi add.c
gensees-iMac:study gensee$ clang -g -c add.c
gensees-iMac:study gensee$ ls add.o
add.o
gensees-iMac:study gensee$ ./add.o
gensees-iMac:study gensee$ libtool -static -o libmylib.a add.o

生成了一个lib文件
在这里插入图片描述
Ex: 这里使用ar命令可以查看静态库的组成

gensees-iMac:study gensee$ ar -t /Users/gensee/Desktop/study/libmylib.a 
__.SYMDEF SORTED
add.o

arlinux命令,更多查看 https://www.runoob.com/linux/linux-comm-ar.html

创建一个main函数文件 main.c,并编译为.o

#include <stdio.h>
#include "add.h"  
int main()
{
   int sum = add(1,5);
   printf("%d\n",sum);
   return 0;
}
clang -g -c main.c

这里同样我们也需要创建一个add.h头文件以便引用
使用vi add.h

#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
int add(int a, int b);
#endif 

然后我们进行链接

clang -o main main.o -L . -lmylib
gensees-iMac:study gensee$  clang -o main main.o -L . -lmylib
gensees-iMac:study gensee$ ./main
6
gensees-iMac:study gensee$ 

可以看到最后执行了add方法结果为6


clang 编译指令

前提是编译好mylib

clang -g -o main mian.c -I . -L . -lmylib

-I. 表示当前目录头文件
-L. 表示当前目录lib

gensees-iMac:study gensee$  clang -g -o main main.c -I . -L . -lmylib
gensees-iMac:study gensee$ ./main
6
gensees-iMac:study gensee$ 

链接方式

链接系统的库,三方库,分为动态链接静态链接

静态链接动态链接两者最大的区别就在于链接的时机不一样,静态链接是在形成可执行程序前,而动态链接的进行则是在程序执行时。

静态链接:将源文件中用到的库函数与汇编生成的目标文件.o合并生成可执行文。每一个可执行程序对所有需要的目标文件有一份副本,浪费空间,而且更新需要重新编译形成可执行程序。

动态链接:解决了静态链接浪费空间,更新困难的问题,只需要加载一次,存在内存中,每个程序都可以使用。

指令查看网址:http://c.biancheng.net/view/2375.html


将OC反编译为C

.m编译为cpp

clang -rewrite-objc main.m -o test.cpp

指定架构

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o testMain.cpp

文本部分内容摘自 https://www.jianshu.com/p/94c2a7a311d4

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC/CLANG编译器 的相关文章

随机推荐

  • 一张表快速了解c++test工具Parasoft 和 IBM Logiscope谁更强

    你知道测试金字塔吗 为了用开发实践来扩大测试规模 如何以正确的数量设计合适类型的自动化测试 测试金字塔是一个很好的指南 测试金字塔是一个很好的视觉隐喻 它描述了不同的测试层 以及每一层要做多少测试 Parasoft测试金字塔 虽然测试自动化
  • 解决Intellij IDEA控制台,logger.info(),system.out.println()等中文乱码问题

    文章目录 总说 乱码主要分为如下2种大类 1 编写环境乱码 2 控制台打印乱码 又包含3种 一 解决编写环境乱码 二 解决控制台打印乱码 3种 1 IDEA Tomcate启动时控制台打印乱码 2 log4j的logger info 控制台
  • React Native 入门(三)——js与native互相通信

    使用AndroidStudio打开项目中的android目录 并等待Gradle Build完成 首次Build会花费不少时间 耐心等待 编译成功后如图 首先我们来介绍js调用native方法 1 新建文件夹mymoudles和myreac
  • java基础学习 day21(数组的内存原理)

    1 java内存分配 栈 方法运行时使用的内存 比如main 方法运行 进入栈中运行 方法开始执行时会进栈 代码执行完毕会出栈 堆 存储对象或者数组 用new关键字来创建的 都存储在堆中 new出来的东西会在这块内存中开辟空间并产生地址 方
  • mysql半同步复制安装配置

    一 半同步复制介绍 1 半同步复制产生的起源 默认情况下 MySQL复制是异步的 主服务器将事件写入其二进制日志 但不知道从服务器是否或何时检索并处理它们 对于异步复制 如果主服务器崩溃 它提交的事务可能不会传输到任何从服务器 因此 在这种
  • swing jtextArea滚动条和文字缩放

    当加了滚动条的jtextArea添加滚动事件比如缩放ctrl wheel时 添加的滚动事件和滚动缩放事件会重合 如何让这两个事件同时发生而不会相互干扰呢 也就是滚动条放大缩小时文本不会发生上下滚动 import javax swing im
  • 刷脸支付飞速发展带动了支付技术的变革

    移动支付的飞速发展带动了支付技术的变革 NFC支付 二维码支付 指纹支付等支付方式正活跃在我们的日常生活中 而人脸识别技术的成熟和人们对支付便捷安全性需求的提升 使得刷脸支付逐渐进入大众视野 随着移动支付的飞速发展 聚合支付也迅速渗透到各种
  • Hibernate注解开发关于Id的若干问题

    Hibernate的基本注解注解式开发 Hibernate基本注解 其实在id的注解上 还是有很多有意思的东西 这些东西我们要从Hibernate内置的主键生成策略讲起 Hibernate内置的主键生成策略 一 assigned 主键由外部
  • 【读书笔记->统计学】11-02 总体和样本的估计-总体比例、样本比例、根据总体预测样本比例概念简介

    总体比例与样本比例 假设一个情境 曼帝糖果公司再一次进行了抽样 以便利用调查结果预测 总体中有多大比例的人 可能偏爱曼帝公司的糖球 结果发现 在40个人中有32个人偏爱他们的口香糖球 其余8个人则偏爱竞争对手的口香糖球 首席执行官感兴趣的是
  • 对随机字符串进行排序

    关于对随机字符串进行排序 def createId num salt tp k chars a0v1c2d3e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0v1w2x4y5z6 生成num个随机数 for n in ra
  • QCustomPlot系列(7)-鼠标跟随显示坐标值(也即:十字游标功能)游标可以吸附采样点

    先来个动图看看效果 这个动图中实现的功能有 1 十字线游标的X值跟随鼠标 Y值不跟随 2 游标的Y值跟随鼠标的X值对应的曲线的Y值 可以点击图例 更换游标跟随哪个曲线的Y值 3 游标不会出现在曲线中不存在点上 而是自动吸附到距离鼠标最近的曲
  • ElasticSearch V2.3部署问题

    ElasticSearch V2 3 CentOS 7 3个节点 研究ElasticSearch V2 3 进行了2天 终于搞明白大部分配置信息含义并且部署成功了 主要问题在于之前的没有接触过 并且2 3版本之前的版本区别不小 根据之前的文
  • 【2023】最新基于Spring Cloud的微服务架构分析

    Spring Cloud是一个相对比较新的微服务框架 2016年才推出1 0的release版本 虽然Spring Cloud时间最短 但是相比Dubbo等RPC框架 Spring Cloud提供的全套的分布式系统解决方案 Spring C
  • 【论文阅读翻译】Action Assessment by Joint Relation Graph

    论文阅读翻译 Action Assessment by Joint Relation Graph KeyWords Abstract Introduction Related Work Approach Experiment KeyWord
  • docker基础篇-----04-----命令添加容器数据卷、dockerfile添加容器数据卷、容器间数据卷共享(--volumes-from)

    参考文章 学习笔记 尚硅谷周阳老师的Docker教程学习笔记 一 容器数据卷 1 容器数据卷 1 什么是容器数据卷 容器删除后数据自然也就没有了 所以用卷来保存数据 容器数据卷功能是持久化和数据共享 卷就是目录或文件 存在于一个或多个容器中
  • springboot中ElasticSearch入门与进阶:组合查询、Aggregation聚合查询(你想要的都有)

    1 springboot中配置elasticSearch 1 1在工程中引入相关的jar包 1 1 1 在build gradle中添加需要的jar包 我创建的gradle工程 对应的maven工程也是一样 添加对应的jar包即可 添加 S
  • linux shell 时间运算以及时间差计算方法

    最近一段时间 在处理Shell 脚本时候 遇到时间的处理问题 时间的加减 以及时间差的计算 1 时间加减 这里处理方法 是将基础的时间转变为时间戳 然后 需要增加或者改变时间 变成 秒 如 1990 01 01 01 01 01 加上 1小
  • 3D人脸模型Flame ----《Learning a model of facial shape and expression from 4D scans》论文讲解及代码注释

    前文 在阅读论文前 首先我们要有一定的知识储备 包括人脸建模 表情制作 旋转转换等 才能方便我们的论文理解 所以首先我会讲解一些关键的知识点 Flame模型的作用 Flame是一个3D人脸的通用模型 举个例子 你现在有一个特定人的3D人脸扫
  • LeetCode练习笔记

    c 解法 文章目录 1 两数之和 简单 题目 方法一 两遍哈希表 方法二 一遍哈希表 2 整数反转 中等 题目 解题方法 3 无重复字符的最长子串 中等 解题方法 4 寻找两个正序数组的中位数 难 解题方法 5 腾讯 6 字节跳动 7 腾讯
  • GCC/CLANG编译器

    文章目录 编译指令 编译过程 预处理 生成汇编代码 词法分析 语法分析 语义分析 生成中间代码 代码生成 LLVM IR 汇编 链接 lib库的链接 clang 编译指令 链接方式 将OC反编译为C GCC是在linux下使用的编译器 Cl