4-2、编辑器Vim、编译器GCC、工程构建工具Make
对练习代码进行编译时使用如下指令:
gcc -o main main.cpp
将会报错:
xxx:xxx: undefined reference to `operator new[](unsigned int)'…
解决方案:
因为写的是 C++ 程序
g++ -o main main.cpp
程序开发:将人类想要计算执行的工作按照计算机所支持的方式流程化、格式化、系统化的,使用编译器支持的开发语言组织成文,并由编译器翻译成机器码供计算机执行
C/C++ 程序开发一般包含以下步骤:
vim [filename]
移动
方向键
:1 快速跳转到文件第1行
:$ 快速跳转到文件最后一行
退出
w (保存)、q (退出)、! (强制)
:wq 保存文件并退出 Vim
:q! 强制退出,不保存修改
替换
s,:[addr]s/源字符串/目的字符串/[option]
全局替换:
%s/源字符串/目的字符串/g
2,10s/源字符串/目的字符串/g
例如:在使用vim编辑文件 cal_pi.cpp 时 ,若要把第 20 至 30 行代码中的 val_pi 字符串,一次性全部替换成 pi_value ,需键入命令 :20,30s/val_pi/pi_value/g
只有在插入模式下,才可以做文字输入,i 进入插入模式,按 [ESC] 回到普通模式
选定文段进行操作等,v 或 ctrl + v 进入,方向键选择,按 [ESC] 退出
复制
y 复制光标所选定文段
粘贴
p 在光标所在行处粘贴
删除、裁切
x 删除光标所选文段
使用 Vim 编辑器,编写C语言程序 saxpy
程序saxpy实现了单精度浮点型数据的向量加法运算,其具体公式如下:
y[n]=y[n]+a*x[n]
其中,n为向量长度,x、y为向量数组,a为标量系数,x、y、a均为单精度浮点型float
各变量的初始值如下:
n为102400
a为3.14
x中各元素初始为0.0~6.0间的浮点型随机数
y初始取值为y[n]=12.0-x[n]
程序文件组织如下:
kernel_axpy.h
负责向量加法接口函数的声明如下:
void saxpy(const int a,const float * const x, float *y)
其中,a、x为输入,y即为输入、也为输出
void saxpy(const int a,const float * const x, float *y);
kernel_axpy.cpp
负责向量加法接口函数saxpy()的定义实现
#include "kernel_axpy.h"
using namespace std;
void saxpy(const int a,const float * const x, float *y)
{
for (int i=0; i<102400; ++i)
{
y[i] += a*x[i];
}
}
main.cpp
负责初始化向量
调用向量加法接口saxpy()
使用计时函数clock()统计saxpy()的运行时间,并打印到屏幕
打印结果y的前20个元素数值到文件y_value.txt
#include
#include
#include
#include
#include "kernel_axpy.h"
using namespace std;
const int n = 102400;
const float a = 3.14;
int main()
{
float *x = new float[n];
float *y = new float[n];
srand((unsigned)time(NULL));
for (int i=0; i (rand()) / (static_cast (RAND_MAX/6));
y[i] = 12 - x[i];
}
clock_t startTime, endTime;
startTime = clock();
saxpy(a, x, y);
endTime = clock();
cout<<(double)(endTime - startTime) / CLOCKS_PER_SEC<
生成指定范围的浮点类型随机数: link
clock() 的使用: link
编译过程:预处理、编译、链接
gcc -o [binaryfile] [sourcefile1] [sourefile2]…
例如:
编译处可执行文件:gcc -o HelloWorld main.c
执行:./HelloWorld
编译与链接
示例:需要编译 main.c、kernel.c 成 exe,其使用了 /home/opt/ 路径下的第三方库 math,其中 opt 目录下包含:/include/mymath.h、/lib/mymath.so
gcc -o [obj_file] -c [src_file] -I [include_path]
最后一个是字母 i 的大写不是 l
例如:
gcc -c main.c -o main.o
gcc -c kernel.c -o kernel.o -I /home/opt/include
链接 (将所有目标文件,以及第三方库,链接成二进制文件)
gcc -o [bin] [all_obj_files] -L [library_path] -l [library_file_name]
最后一个是小写字母 l
例如:
gcc -o exe main.o kernel.o -L /home/opt/lib -l mymath
gcc -o [bin] [all_src_files] -I [include_path] -L [library_path] -l [library_file_name]
前面那个 -l 是大写的 i,后面那个 -l 是小写的 L
例如:
gcc -o exe main.c kernel.c -I /home/opt/include -L /home/opt/lib -l mymath
优化等级选项:
-O0,-O1,-O2,-O3 由编译器自动进行代码性能优化,等级越大,程序运行速度越快
警告选项:
-Wall 显示所有警告
调试选项:
-g 通常结合 -O0 优化等级编译,后期可使用 gdb 工具对二进制文件进行调试。会降低程序计算速度
性能分析选项:
-pg 后期可用于 gprof 工具对二进制文件进行性能分析。会降低程序计算速度
宏定义选项
-D 对应着程序代码中的宏定义。如 -DUSE_MPI
- Makefile 组成结构:目标、目标的前置条件 (依赖)、规则,还包括变量以及内置函数
- 一个目标 (最终的执行文件),会依赖一些文件 (如源文件、目标文件、库文件等),所依赖的文件也可以作为新的目标 (子目标) 放在后面,建立其对应的规则
- 执行 make 指令时,make首先执行的是 Makefile 里面的第一个目标,检查第一个目标的前置条件,然后寻找 “前置条件” 的前置条件,以此类推
- 执行某个特定的目标,不遵循默认从第一个目标开始,则输入:
make [targetName]
BIN=hello "="定义变量BIN: 要生成的二进制文件名称为"hello"
SRC=hello.cpp
all:$(BIN) all为make默认执行目标, 这个目标所依赖文件: 二进制文件BIN
$(BIN):$(SRC) 二进制文件BIN依赖于源码文件SRC
g++ -o $(BIN) $(SRC) 建立SRC到BIN的规则
clean: clean 目标不依赖任何其他, 执行时将执行文件删除命令
rm -rf $(BIN) $(OBJ)
- 安装可执行文件:make
- 清除:make clean
现有一个程序,包含main.cpp、kernel.cpp源文件,并使用了/home/opt/路径下的第三方库mymath,其中opt路径下包含头文件./include/mymath.h和库文件./lib/libmymath.so。需要在与源文件同级目录下编写makefile文件来安装该程序,来编译出二进制文件exe
BIN=exe
OBJ=main.o kernel.o
CXX=g++
CXXFLAGS=-O2
LDFLAGS=$(CXXFLAGS)
INC=-I/home/opt/include
LIB=-L/home/opt/lib -lmymath
ALL:$(BIN)
$(BIN):$(OBJ)
$(CXX) $(LDFLAGS) -o $@ $^ $(LIB)
%.o:%.cpp
$(CXX) $(CXXFLAGS) -o $@ -c $< $(INC)
.PHONY:clean
clean:
rm -rf $(OBJ) $(BIN)
今天的内容比较硬核,虽然之前或多或少了解过,但再次接触依然比较陌生。虽然把课程和任务过了一遍,但应该只是接触了这部分的皮毛,之后再遇到问题时还是要多查、多悟
作业管理系统slurm、调试器GDB、高性能算法等
课程终端好卡…