文章目录
前言
最近在弄一个比赛,要使用到C编程,自己之前一般都是用集成化的IDE进行C的编程,对于使用gcc,g++直接编译代码属实不了解,了解了一下相关使用,并学习了一些基础的makefile语法知识,写下工作总结
一、gcc使用
https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/Overall-Options.html#Overall-Options
官方文档
查看gcc版本
gcc --version
无任何编译选项
编译.c文件,并链接成可执行文件。默认输出名字a.out,输出文件到当前目录下。
gcc main.c
选项 -o
指定输出的文件名字
gcc main.c -o main.o
选项 -E
预处理阶段后停止;不运行编译器。输出采用预处理源代码的形式,发送到标准输出。即会生成.i结尾的文件
预处理功能主要包括宏定义, 文件包含, 条件编译, 去注释等。
预处理指令是以 # 号开头的代码行。
file.c:必须预处理的 C 源代码。
file.i:不应预处理的 C 源代码。
file.ii:不应预处理的 C++ 源代码。
gcc -E main.c -o main.i
选项 -S
编译成汇编语言但不进行链接
gcc -S main.c -o main.s
gcc -S main.i -o main.s
选项 -c
编译文件到目标文件,但不进行链接
gcc -c main.c -o main.o
链接生成可执行文件
将所有.o文件进行链接,生成可执行文件,默认动态链接
gcc main.o test.o -c main # 将目标文件进行链接
gcc main.c test.c -o main #一步生成可执行文件
-static 此选项对生成的文件采用静态链接
gcc main.c test.c -o main_Static --static
链接分为两种:
动态链接:GCC编译时的默认选项。动态是指在应用程序运行时才去加载外部的代码库,不同的程序可以共用代码库。 所以动态链接生成的程序比较小,占用较少的内存。
静态链接:链接时使用选项 “–static”,它在编译阶段就会把所有用到的库打包到自己的可执行程序中。 所以静态链接的优点是具有较好的兼容性,不依赖外部环境,但是生成的程序比较大。
代码优化 -O
-O0 -O1 -O2 -O3 编译器的优化选项的 4 个级别, -O0 表示没有优化 ,-O3 优化级别最高。-O3的优化会比较暴力,但优化效果很好
gcc main.c -O1 -o main
编译所需文件目录 -I
我们在写代码的时候,为了整个工程的美观性和便于整理代码,一般会将.c和.h分开,-I 目录名称
可以让gcc找到需要链接的文件目录
gcc main.c -I ./inc -o main #包含inc中的所有文件
其他
-g
生成调试信息。 GNU 调试器可利用该信息
-lpthread
文件中若包含多线程
pkg-config opencv --libs
包含opencv的C++库
二、Makefile文件
如果我们每次都输入一长串编译的指令的时候,会非常的麻烦,而makefile可以简化我们的需要。
makefile一个最关键的语法规则如下,代表了你需要生成什么目标,其依赖部分是什么,后续执行操作就放在命令中。
目标...: 依赖...
命令1
命令2
...
一些特殊变量
$@:目标的名字
$^:构造所需文件列表所有所有文件的名字
$<:构造所需文件列表的第一个文件的名字
$?:构造所需文件列表中更新过的文件
具体知识可以参考下面的博客
https://blog.youkuaiyun.com/afei__/article/details/82696682
https://blog.youkuaiyun.com/BobYuan888/article/details/88640923
先摆一个最近自己用的Makefile文件,以后自己也可以方便用。这里面包含了c++和c语言的混合编译的部分
Makefile例子
BIN_DIR = bin
SRC_DIR = src
INC_DIR = inc
OBJ_DIR = obj
CC = gcc
C++ = g++
LD = gcc #链接所需用的编译器
INC = -I$(INC_DIR)
CFLAGS += $(INC)
OPT = -O1
LDFLAGS = -lm
# C文件
OBJ_FILES_C = $(OBJ_DIR)/main.o \
$(OBJ_DIR)/jpeg.o \
$(OBJ_DIR)/show.o \
$(OBJ_DIR)/huff.o
# 所有文件
OBJ_FILES = $(OBJ_FILES_C)
#总链接可执行文件gcode的位置
TARGET = $(BIN_DIR)/gcode
# all代表最终生成文件
all: $(TARGET)
# c文件编译
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(OPT) -c $< -o $@
# cpp文件编译
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(C++) $(CFLAGS) $(OPT) -c $< -o $@
# 如果要链接别的库的话,必须要在最后所有.o文件链接为一个文件的时候链接opencv库
# 如果在生成.o文件的时候链接会导致最终找不到该库
$(TARGET) : $(OBJ_FILES_C)
$(C++) $(LDFLAGS) $(OBJ_FILES_C) $(OPT) -o $@ -lpthread
# -lpthread代表代码中包含多线程执行
# $(C++) $(LDFLAGS) $(OBJ_FILES) -o $@ `pkg-config opencv --libs` #若包含opencv库需要链接
@echo "> build success <"
#make clean指令
clean:
rm -f $(TARGET) $(OBJ_FILES)
三、C和C++混合编程
C++调用C函数
通常为了C代码能够通用,即既能被C调用,又能被C++调用,头文件通常会有如下写法:
#ifdef __cplusplus
extern "C"{
#endif
int add(int x,int y);
#ifdef __cplusplus
}
#endif
//或者
//xx.h
extern int add(...)
//xx.c
int add(){
}
//xx.cpp
extern "C" {
#include "xx.h"
}
C函数调用C++函数
在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。所以使用extern "C"全部都放在于cpp程序相关文件或其头文件中。
//xx.h
extern "C"{
int add();
}
//xx.cpp
int add(){
}
//xx.c
extern int add();
不过与C++调用C接口不同,C++确实是能够调用编译好的C函数,而这里C调用C++,不过是把C++代码当成C代码编译后调用而已。也就是说,C并不能直接调用C++库函数。
放篇博客
https://blog.youkuaiyun.com/this_is_me_anyway/article/details/79397018
参考
gcc部分
https://zhuanlan.zhihu.com/p/404682058
https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/Overall-Options.html#Overall-Options
Makefile部分
https://blog.youkuaiyun.com/BobYuan888/article/details/88640923
https://blog.youkuaiyun.com/afei__/article/details/82696682