Linux C从入门到进阶

Posted by JackPeng on September 16, 2018

Linux C 和Windows C

  • 标准C,ANSI-C
  • Windows C
  • Linux C

GCC 编译器

GNU编译器套件(GNU Compiler Collection) GNU:是GNU is Not Unix的递归缩写,即类Unix操作系统 Linux:Linux Is Not UniX PNG:PNG’s Not GIF RPM:RPM Package Manager

![](

GCC 安装

mac一般自带gcc,通过gcc --version,查看gcc版本; CentOS 安装:yum install gcc 默认已安装; Ubuntu 安装:apt-get install gcc 默认已安装;

GCC常用命令

命令参数 说明
–help 帮助信息
-save-temps 不删除中间文件
-Werror 所有警告当做是错误
-w 不显示警告
-m32/-m64 生成32/64位程序
-D 追加宏定义
-L 追加库文件目录
-l 追加库文件
-I 追加头文件目录
-include 追加头文件

查看完整信息,采用命令man gcc

hello gcc

编写hello world程序如下:

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("hello world\n");
    return 0;
}

分步编译如下(其中输出扩展名可以自定义):

gcc -E hello.c -o hello.i #预编译,输出hello.i
gcc -S hello.i -o hello.s #编译,生成hello.s
gcc -c hello.s -o hello.o #汇编,生成hello.o
gcc hello.o -o hello #链接,生成可执行程序hello
./hello # 执行可执行程序hello

这几步等价于 gcc hello.c -o hello; 如果没有指定-o参数,默认输出为a.out 编译32位程序 gcc -m32 hello.c -o hello32; 编译64位程序 gcc -m64 hello.c -o hello64; 查看可执行程序是32或64位命令:

personal:projects apple$ file hello
hello: Mach-O 64-bit executable x86_64
personal:projects apple$ file hello32
hello32: Mach-O executable i386
personal:projects apple$ file hello64
hello64: Mach-O 64-bit executable x86_64

gcc默认按当前系统是32还是64位编译cx,查看系统位数的命令是:uname

personal:projects apple$ uname -a
Darwin personal.local 16.1.0 Darwin Kernel Version 16.1.0: Thu Oct 13 21:26:57 PDT 2016; root:xnu-3789.21.3~60/RELEASE_X86_64 x86_64

多文件编译

多文件编译遵循一条原则:

  • 头文件,无需在gcc中指定,因此头文件的个数不影响编译结果;
  • 源文件:gcc a.c,b.c -o 源文件顺序可调。 提高编译速度的技巧,假设有多个文件a.c,b.c,可分开编译到汇编这一步,最后链接时再一块编译,以后a或b有变化时,无需全量编译,只编译有修改的源文件,再执行链接就可以了。
gcc -c a.c -o a.o # 执行到汇编这步
gcc -c b.c -o b.o
gcc a.o b.o -o hello #链接生成可执行程序

GDB调试

GDB简介

GDB:GNU DeBuger,与GCC配套的调试工具 ; man gdb 查看帮助手册; mac上gdb安装和使用参考: https://blog.csdn.net/github_33873969/article/details/78511733

GDB 常用命令

要想使用gdb调试,需要在使用gcc编译时指定-g参数: 在目标文件加入源代码 gcc -g xxx.c -o xxx

gdb xxx 开始调试,进入gdb控制台
(gdb) list 或者 l 列出所有代码 
(gdb) run 或者 r 运行程序
(gdb) start 开始调试
(gdb) quit 或者 q 退出调试
(gdb) next 或者 n 运行下一行,仅在当前函数
(gdb) step 或者 s 运行下一行,可进入函数
(gdb) print 或者 p 变量名 打印变量当前值
(gdb) set var i=3 局部变量设置
(gdb) info 或者 i 查看信息 locals 查看当前变量
(gdb) break 或者 b 设置断点,接行号或函数
(gdb) continue 或者 c   继续运行,直到下一个断点
(gdb) info 或者i breakpoints 列出断点
(gdb) delete或者d 删除断点

静态链接库和动态链接库

静态库和动态库的定义和特点可以参考:

https://www.cnblogs.com/king-lps/p/7757919.html

静态链接库

静态库是二进制文件,可链接为可执行文件,以提供功能函数为主要目的,可被其他库或可执行文件调用,且与他们无依赖关系。在Windows系统扩展名为.lib,linux和mac系统扩展名为.a;

静态链接库编译

静态链接库编译和打包流程如下:

  • step 1,源文件编译到汇编的目标文件,gcc -c xxx.c -o xxx.o;
  • step 2,有两种方式:
    • ar rs libxxx.a xxx.o,把目标文件xxx.o打包成静态库文件libxxx.a;
    • ar r libxxx.a xxx.o ranlib libxxx.a,使用ranlib来对静态库的符号索引表进行更新.
  • step 3,gcc main.c -L. -lxxx -o main,使用静态链接库编译可执行程序,-L.指添加当前目录为库目录,-lxxx指添加名为xxx的库。

代码实战

新建代码文件如下:

#test1.h
int sum(int a,int b);

# test1.c
#include "test1.h"

int sum(int a,int b){
	return a+b;
}

# test2.h
int sub(int a,int b);

# test2.c
#include "test2.h"
int sub(int a,int b){
	return a-b;
}

#demo.c
#include <stdio.h>
#include "test1.h"
#include "test2.h"

int main(){
	int x = 5;
	int y = 3;
	int ret = sum(x,y);
	printf("%d+%d=%d\n",x,y,sum(x,y));
	printf("%d-%d=%d\n",x,y,sub(x,y));
	return 0;
}

执行命令如下:

guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
demo.c	test1.c	test1.h	test2.c	test2.h
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc -c test1.c -o test1.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
demo.c	test1.c	test1.h	test1.o	test2.c	test2.h
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc -c test2.c -o test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
demo.c	test1.c	test1.h	test1.o	test2.c	test2.h	test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ar rs libcalc.a test1.o test2.o
ar: creating archive libcalc.a
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
demo.c		test1.c		test1.o		test2.h
libcalc.a	test1.h		test2.c		test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc demo.c -L. -lcalc -o demo
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
demo		libcalc.a	test1.h		test2.c		test2.o
demo.c		test1.c		test1.o		test2.h
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ./demo
5+3=8
5-3=2

可执行程序不依赖静态库验证:

guangjiepengdeMacBook-Pro:demo guangjie.peng$ mv demo ../demo2
guangjiepengdeMacBook-Pro:demo guangjie.peng$ cd ..
guangjiepengdeMacBook-Pro:Downloads guangjie.peng$ ./demo2
5+3=8
5-3=2

ar类似命令tar,也可以解压静态库:

guangjiepengdeMacBook-Pro:demo guangjie.peng$ rm -rf test1.o test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	test1.c			test2.h
demo.c			test1.h
libcalc.a		test2.c
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ar -x libcalc.a 
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	test1.c			test2.c
demo.c			test1.h			test2.h
libcalc.a		test1.o			test2.o

使用clion创建静态库

  • 创建:在创建project时可以选择可执行过程还是library过程,以及选择静态库和动态库。demo工程如下:

  • Build,Run->Build,会在cmake-build-debug目录生成.a静态库文件;

使用Clion调用静态库

  • 拷贝创建好的静态库libhellolibrary.a和library.h到clion根目录;

    #library.h
    #ifndef HELLOLIBRARY_LIBRARY_H
      #define HELLOLIBRARY_LIBRARY_H
      void hello();
      #endif
        
    #library.cpp
    #include "library.h"
    #include <iostream>
    void hello() {
      std::cout << "Hello, Library!" << std::endl;
    } 
    
    
  • 打开clion工程的CMakeLists.txt,添加要链接的静态库,如下:

cmake_minimum_required(VERSION 3.10)
project(clion)

set(CMAKE_CXX_STANDARD 11)
set(LIB_DIR /Users/guangjie.peng/development/clion)#定义变量
link_libraries(${LIB_DIR}/libhellolibrary.a)#指定要链接的静态库
  • 在clion中调用静态库的方法:

    void testStaticLibrary(){
      hello();
    }
    

动态链接库

动态链接库打包过程

动态库之间以及与调用程序之间存在依赖关系.

  • step 1,gcc -fPIC -c xxx.c -o xxx.o,编译目标文件时增加-fPIC 参数;
  • step 2,gcc -shared xxx.o -o libxxx.so,打包so库;
  • step 3,gcc main.c -L. -lxxx -o main,与可执行文件链接。
  • step 4,mac上可直接执行:./main,Linux上需要把so库拷贝到/usr/lib/目录,然后执行ldconfig命令;

代码实战

复用静态库demo代码,执行命令如下:

guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	demo.c			test1.c			test1.h			test2.c			test2.h
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc -fPIC -c test1.c test2.c
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	test1.c			test1.o			test2.h
demo.c			test1.h			test2.c			test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc -shared test1.o test2.o -o libcalc.so
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	libcalc.so		test1.h			test2.c			test2.o
demo.c			test1.c			test1.o			test2.h
guangjiepengdeMacBook-Pro:demo guangjie.peng$ gcc demo.c -L. -lcalc -o demos
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ls
__.SYMDEF SORTED	demos			test1.c			test1.o			test2.h
demo.c			libcalc.so		test1.h			test2.c			test2.o
guangjiepengdeMacBook-Pro:demo guangjie.peng$ ./demos
5+3=8
5-3=2

尝试删除so库,看demo是否能正常运行:

guangjiepengdeMacBook-Pro:demo guangjie.peng$ ./demos
dyld: Library not loaded: libcalc.so
  Referenced from: /Users/guangjie.peng/Downloads/demo/./demos
  Reason: image not found
Trace/BPT trap: 5

Clion创建动态链接库验证

流程同静态库,选择shared library就可以了;

调用动态链接库

  • step 1,同样拷贝so和头文件到调用工程根目录下;
  • step 2,编辑CMakeLists.txt文件,加入如下代码: target_link_libraries(clion /Users/guangjie.peng/development/clion/libhellolibrary.so)