OOP 学习笔记(1)——编程环境与基本技能
Contents
编程环境与基本技能
源程序结构
- 头文件与编译指令;
- 辅助函数定义;
- 主函数定义。
编译与链接
编译器
把源代码转化为汇编语言或机器指令。
链接器
把各段程序链接为一个完整的可执行程序。
实例
其中 g++ -c
是只编译不链接,后面的 g++ -o
代表把编译好的 1.o
文件链接成可执行文件 1.out
。
多个源文件的编译和链接
建议函数声明与定义分离,将声明放至对应名字的头文件 .h
中。
如 func.h
中:
int ADD(int a,int b);
func.cpp
中:
#include "func.h"
int ADD(int a,int b)
{
return a+b;
}
main.cpp
中:
#include "func.h"
int main()
{
//...
}
可以采用直接编译的方法:
g++ main.cpp func.cpp -o test1
(建议省略头文件)
也可以采用间接编译:
g++ -c main.cpp -o main.o
g++ -c func.cpp -o func.o
g++ main.o func.o -o test2
得到效果相同。
宏定义
利用部分提到过的宏定义可以防止头文件被重复包含:
#ifndef __BODYDEF_H__
#define __BODYDEF_H__
// 头文件内容
#endif
也可以更简单:
#pragma once
// 头文件内容
其可保证物理上的同一个文件不会被编译多次。
同样也可以利用宏定义来设置输出调试相关信息。
主流编译器以及 IDE
编译器
- MinGW:Minimalist GNU For Windows,是用于 Windows 平台 C/C++、ADA、Fortran 语言的编译器。
- TDM-GCC:Windows 版的编译器套件,结合了 GCC 工具集中最新的稳定发行版本。
其他系统安装
- Linux:
sudo apt-get install build-essential
- Mac:
brew install gcc
IDE
- DEV C++
- Code::Blocks
- Visual Studio
- CLion
- XCode
Editor
- Notepad++
- SublimeText
- VIM
- Visual Studio Code
CLion
- CLion:Free for student
Github:Student Developer Pack
通过 CMake 生成 makefile 文件
支持 Git 进行代码版本控制
C++11
本教程内容均使用 C++11 标准。
g++ -v
可以确认 g++ 版本 $\ge 4.7$。以 C++11 标准编译:
g++ -std=c++11 1.cpp -o 1
- IDE 中一般也可以选择 C++ 标准。
MAKE 工具
- 使得大型编译工作自动化的一种工具:
- 减少编译程序花费的时间。
- 确保使用正确的选项进行编译。
- 确保链接正确的程序模块和程序库。
- 根据其机制,还可以:
- 简化任务的重复执行过程。
- 减少说明文档的编写工作量。
- 其它创新性的想法。
Makefile 编写规则
- 如果工程没有编译过,则所有
.cpp
文件均要编译并被链接。 - 如果某几个
.cpp
文件修改,只编译修改的.cpp
文件,并链接目标程序。 - 如果工程的头文件被改变了,需要编译引用了这几个头文件的
.cpp
文件,并链接目标程序。
格式:
<target>: <prerequisites>
[tab] <command>
prerequisites
中如果有至少一个文件比 target
文件要新的话, command
命令就会被执行。
注释以 #
开头即可。
一个示例文件如下:
# OOP @ 20200130
all: main.exe test.exe
main.exe: main.cpp student.cpp
g++ -o main.exe main.cpp student.cpp
test.exe: student.cpp student_test.cpp
g++ -o test.exe student_test.cpp student.cpp
clean:
del *.exe
编写 Makefile 的基本方法
- 从一个例子入手;
- 列出源程序清单;
- 搞清楚几个最基本的编译器参数选项;
- 更多 Make 用法:http://www.ruanyifeng.com/blog/2015/02/make.html
除此之外还有几个可以用于提高效率的 MAKE 宏:
$@
代表目标的全名(含后缀)。$@
指代当前目标,也就是 Make 命令构建的目标。- 比如
make foo
时$@
就指代foo
。
$*
代表无后缀的目标名。$*
指代匹配符%
匹配的部分。- 比如
%
匹配f1.txt
中的f1
则$*
就表示f1
。
$<
代表规则中的源程序名。$<
代表第一个前置条件。- 比如,规则为:
t: p1 p2
,则$<
指代p1
。
%
:比如%.o: %.c
就相当于f1.o: f1.c
和f2.o: f2.c
等等。
运行 Makefile 的基本方法
make
make 任务名
make -f makefile的文件名
make -f makefile的文件名 任务名
尝试理解一个开源项目中的 Makefile 文件
https://github.com/moses-smt/giza-pp
.PHONY: gizapp mkcls-v2
all: gizapp mkcls-v2
gizapp:
$(MAKE) -C GIZA++-v2
mkcls-v2:
$(MAKE) -C mkcls-v2
clean:
$(MAKE) -C GIZA++-v2 clean
$(MAKE) -C mkcls-v2 clean
其中 .PHONY
后内容无视目标文件存在与否都执行 command
,避免与工作目录下同名文件夹冲突。
可以使用 Var = 字符串
的形式定义变量宏。
预定义:$(MAKE) = make
。
make -C [target]:
则表示切换到 [target]
文件夹执行 Make 命令。
make -p
可查看所有预定义。
make -h
可查看帮助。
子文件夹:GIZA++-v2
中 Makefile 文件
.SUFFIXES: .out .o .c .e .r .f .y .l .s .p .cpp .alpha2o .pentiumo .sgio .alphao # 该Makefile所支持后缀类型
INSTALLDIR ?= /usr/local/bin/ # 使用“?=”进行赋值的时候如果该变量已经赋值过了,那么将跳过
CXX = g++ # 后面统一使用 CXX 编译
CFLAGS = $(CFLAGS_GLOBAL) -Wall -Wno-parentheses
CFLAGS_OPT = $(CFLAGS) -O3 -funroll-loops -DNDEBUG -DWORDINDEX_WITH_4_BYTE -DBINARY_SEARCH_FOR_TTABLE
CFLAGS_PRF = $(CFLAGS) -O2 -pg -DNDEBUG -DWORDINDEX_WITH_4_BYTE
... ...
LDFLAGS =
include Makefile.src
OBJ_DIR_OPT = optimized/
OBJ_OPT = ${SRC:%.cpp=$(OBJ_DIR_OPT)%.o} # %为匹配符
# 提取SRC中所有.cpp的前缀,构成OBJ_DIR_OPT+前缀值.o的集合
OBJ_DIR =
GIZA++: $(OBJ_DIR_OPT) $(OBJ_OPT) # 将.o文件一起链接为GIZA++
$(CXX) $(OBJ_OPT) $(LDFLAGS) -o GIZA++
$(OBJ_DIR_OPT): $(OBJ_DIR) # 创建文件夹
-mkdir $(OBJ_DIR_OPT)
$(OBJ_DIR_OPT)%.o: %.cpp # 编译所有cpp
$(CXX) $(CFLAGS_OPT) -c $< -o $@
... ...
其中 Makefile.src
中:
SRC = Parameter.cpp myassert.cpp ...
GIZA++-v2
文件夹下有 $30$ 个 .cpp
文件。
OBJ_DIR
为空但不影响理解。
Comments: 7
图片挂了
fixed
TDM-GCC 已经停更好久了。现在最新版 GCC 是 9.2,TDM 还是 5.1。
还有这个
这个咋又挂了。。
是我魔改markdown parser出锅了,这会儿就先改下格式算了。